fontisan 0.4.7 → 0.4.8
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/CHANGELOG.md +13 -0
- data/docs/.vitepress/config.ts +0 -7
- data/docs/cli/index.md +5 -28
- data/docs/index.md +0 -2
- data/lib/fontisan/cli.rb +29 -8
- data/lib/fontisan/collection/reader/stats.rb +23 -0
- data/lib/fontisan/collection/reader.rb +90 -0
- data/lib/fontisan/collection.rb +1 -0
- data/lib/fontisan/commands/convert_command.rb +96 -18
- data/lib/fontisan/commands/multi_format_output.rb +59 -0
- data/lib/fontisan/commands/validate_collection_command.rb +121 -0
- data/lib/fontisan/commands.rb +2 -0
- data/lib/fontisan/error.rb +25 -0
- data/lib/fontisan/models.rb +0 -1
- data/lib/fontisan/stitcher/collection_result.rb +18 -0
- data/lib/fontisan/stitcher/partition_strategy/base.rb +23 -0
- data/lib/fontisan/stitcher/partition_strategy/blueprint.rb +24 -0
- data/lib/fontisan/stitcher/partition_strategy/by_plane.rb +131 -0
- data/lib/fontisan/stitcher/partition_strategy/partition.rb +24 -0
- data/lib/fontisan/stitcher/partition_strategy.rb +22 -0
- data/lib/fontisan/stitcher.rb +44 -10
- data/lib/fontisan/ufo/compile/name.rb +2 -2
- data/lib/fontisan/ufo/info.rb +48 -0
- data/lib/fontisan/unicode/plane.rb +56 -0
- data/lib/fontisan/unicode.rb +17 -0
- data/lib/fontisan/version.rb +1 -1
- data/lib/fontisan.rb +2 -2
- metadata +13 -18
- data/docs/cli/audit.md +0 -337
- data/lib/fontisan/cldr/aggregator.rb +0 -33
- data/lib/fontisan/cldr/cache_manager.rb +0 -110
- data/lib/fontisan/cldr/config.rb +0 -59
- data/lib/fontisan/cldr/download_error.rb +0 -9
- data/lib/fontisan/cldr/downloader.rb +0 -79
- data/lib/fontisan/cldr/error.rb +0 -8
- data/lib/fontisan/cldr/index.rb +0 -64
- data/lib/fontisan/cldr/index_builder.rb +0 -72
- data/lib/fontisan/cldr/unicode_set_parser.rb +0 -189
- data/lib/fontisan/cldr/unknown_version_error.rb +0 -9
- data/lib/fontisan/cldr/version_resolver.rb +0 -91
- data/lib/fontisan/cldr.rb +0 -23
- data/lib/fontisan/cli/cldr_cli.rb +0 -85
- data/lib/fontisan/config/cldr.yml +0 -22
- data/lib/fontisan/models/cldr/language_coverage.rb +0 -31
- data/lib/fontisan/models/cldr.rb +0 -12
data/lib/fontisan.rb
CHANGED
|
@@ -72,10 +72,10 @@ module Fontisan
|
|
|
72
72
|
autoload :VariationDataCorruptedError, "fontisan/error"
|
|
73
73
|
autoload :MultipleCbdtSourcesError, "fontisan/error"
|
|
74
74
|
autoload :GlyphLimitExceededError, "fontisan/error"
|
|
75
|
+
autoload :PartitionCapExceededError, "fontisan/error"
|
|
75
76
|
|
|
76
77
|
# Namespace hubs (each hub declares its own child autoloads)
|
|
77
78
|
autoload :Binary, "fontisan/binary"
|
|
78
|
-
autoload :Cldr, "fontisan/cldr"
|
|
79
79
|
autoload :Collection, "fontisan/collection"
|
|
80
80
|
autoload :Commands, "fontisan/commands"
|
|
81
81
|
autoload :Converters, "fontisan/converters"
|
|
@@ -92,6 +92,7 @@ module Fontisan
|
|
|
92
92
|
autoload :Tables, "fontisan/tables"
|
|
93
93
|
autoload :Type1, "fontisan/type1"
|
|
94
94
|
autoload :Ufo, "fontisan/ufo"
|
|
95
|
+
autoload :Unicode, "fontisan/unicode"
|
|
95
96
|
autoload :Utilities, "fontisan/utilities"
|
|
96
97
|
autoload :Utils, "fontisan/utils"
|
|
97
98
|
autoload :Validation, "fontisan/validation"
|
|
@@ -120,7 +121,6 @@ module Fontisan
|
|
|
120
121
|
autoload :TrueTypeFont, "fontisan/true_type_font"
|
|
121
122
|
autoload :TrueTypeFontExtensions, "fontisan/true_type_font_extensions"
|
|
122
123
|
autoload :Type1Font, "fontisan/type1_font"
|
|
123
|
-
autoload :CldrCli, "fontisan/cli/cldr_cli"
|
|
124
124
|
autoload :Woff2Font, "fontisan/woff2_font"
|
|
125
125
|
autoload :WoffFont, "fontisan/woff_font"
|
|
126
126
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fontisan
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.4.
|
|
4
|
+
version: 0.4.8
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose Inc.
|
|
@@ -173,7 +173,6 @@ files:
|
|
|
173
173
|
- docs/api/validators/font-validator.md
|
|
174
174
|
- docs/api/validators/helper.md
|
|
175
175
|
- docs/api/validators/profile.md
|
|
176
|
-
- docs/cli/audit.md
|
|
177
176
|
- docs/cli/convert.md
|
|
178
177
|
- docs/cli/dump-table.md
|
|
179
178
|
- docs/cli/export.md
|
|
@@ -277,24 +276,13 @@ files:
|
|
|
277
276
|
- lib/fontisan/binary.rb
|
|
278
277
|
- lib/fontisan/binary/base_record.rb
|
|
279
278
|
- lib/fontisan/binary/structures.rb
|
|
280
|
-
- lib/fontisan/cldr.rb
|
|
281
|
-
- lib/fontisan/cldr/aggregator.rb
|
|
282
|
-
- lib/fontisan/cldr/cache_manager.rb
|
|
283
|
-
- lib/fontisan/cldr/config.rb
|
|
284
|
-
- lib/fontisan/cldr/download_error.rb
|
|
285
|
-
- lib/fontisan/cldr/downloader.rb
|
|
286
|
-
- lib/fontisan/cldr/error.rb
|
|
287
|
-
- lib/fontisan/cldr/index.rb
|
|
288
|
-
- lib/fontisan/cldr/index_builder.rb
|
|
289
|
-
- lib/fontisan/cldr/unicode_set_parser.rb
|
|
290
|
-
- lib/fontisan/cldr/unknown_version_error.rb
|
|
291
|
-
- lib/fontisan/cldr/version_resolver.rb
|
|
292
279
|
- lib/fontisan/cli.rb
|
|
293
|
-
- lib/fontisan/cli/cldr_cli.rb
|
|
294
280
|
- lib/fontisan/collection.rb
|
|
295
281
|
- lib/fontisan/collection/builder.rb
|
|
296
282
|
- lib/fontisan/collection/dfont_builder.rb
|
|
297
283
|
- lib/fontisan/collection/offset_calculator.rb
|
|
284
|
+
- lib/fontisan/collection/reader.rb
|
|
285
|
+
- lib/fontisan/collection/reader/stats.rb
|
|
298
286
|
- lib/fontisan/collection/shared_logic.rb
|
|
299
287
|
- lib/fontisan/collection/table_analyzer.rb
|
|
300
288
|
- lib/fontisan/collection/table_deduplicator.rb
|
|
@@ -309,6 +297,7 @@ files:
|
|
|
309
297
|
- lib/fontisan/commands/info_command.rb
|
|
310
298
|
- lib/fontisan/commands/instance_command.rb
|
|
311
299
|
- lib/fontisan/commands/ls_command.rb
|
|
300
|
+
- lib/fontisan/commands/multi_format_output.rb
|
|
312
301
|
- lib/fontisan/commands/optical_size_command.rb
|
|
313
302
|
- lib/fontisan/commands/pack_command.rb
|
|
314
303
|
- lib/fontisan/commands/scripts_command.rb
|
|
@@ -316,9 +305,9 @@ files:
|
|
|
316
305
|
- lib/fontisan/commands/tables_command.rb
|
|
317
306
|
- lib/fontisan/commands/unicode_command.rb
|
|
318
307
|
- lib/fontisan/commands/unpack_command.rb
|
|
308
|
+
- lib/fontisan/commands/validate_collection_command.rb
|
|
319
309
|
- lib/fontisan/commands/validate_command.rb
|
|
320
310
|
- lib/fontisan/commands/variable_command.rb
|
|
321
|
-
- lib/fontisan/config/cldr.yml
|
|
322
311
|
- lib/fontisan/config/collection_settings.yml
|
|
323
312
|
- lib/fontisan/config/conversion_matrix.yml
|
|
324
313
|
- lib/fontisan/config/export_settings.yml
|
|
@@ -379,8 +368,6 @@ files:
|
|
|
379
368
|
- lib/fontisan/models/all_scripts_features_info.rb
|
|
380
369
|
- lib/fontisan/models/bitmap_glyph.rb
|
|
381
370
|
- lib/fontisan/models/bitmap_strike.rb
|
|
382
|
-
- lib/fontisan/models/cldr.rb
|
|
383
|
-
- lib/fontisan/models/cldr/language_coverage.rb
|
|
384
371
|
- lib/fontisan/models/collection_brief_info.rb
|
|
385
372
|
- lib/fontisan/models/collection_font_summary.rb
|
|
386
373
|
- lib/fontisan/models/collection_info.rb
|
|
@@ -444,9 +431,15 @@ files:
|
|
|
444
431
|
- lib/fontisan/sfnt_font.rb
|
|
445
432
|
- lib/fontisan/sfnt_table.rb
|
|
446
433
|
- lib/fontisan/stitcher.rb
|
|
434
|
+
- lib/fontisan/stitcher/collection_result.rb
|
|
447
435
|
- lib/fontisan/stitcher/deduplicator.rb
|
|
448
436
|
- lib/fontisan/stitcher/glyph_limit.rb
|
|
449
437
|
- lib/fontisan/stitcher/glyph_signature.rb
|
|
438
|
+
- lib/fontisan/stitcher/partition_strategy.rb
|
|
439
|
+
- lib/fontisan/stitcher/partition_strategy/base.rb
|
|
440
|
+
- lib/fontisan/stitcher/partition_strategy/blueprint.rb
|
|
441
|
+
- lib/fontisan/stitcher/partition_strategy/by_plane.rb
|
|
442
|
+
- lib/fontisan/stitcher/partition_strategy/partition.rb
|
|
450
443
|
- lib/fontisan/stitcher/selector.rb
|
|
451
444
|
- lib/fontisan/stitcher/selector/codepoints.rb
|
|
452
445
|
- lib/fontisan/stitcher/selector/gid.rb
|
|
@@ -642,6 +635,8 @@ files:
|
|
|
642
635
|
- lib/fontisan/ufo/reader.rb
|
|
643
636
|
- lib/fontisan/ufo/transformation.rb
|
|
644
637
|
- lib/fontisan/ufo/writer.rb
|
|
638
|
+
- lib/fontisan/unicode.rb
|
|
639
|
+
- lib/fontisan/unicode/plane.rb
|
|
645
640
|
- lib/fontisan/utilities.rb
|
|
646
641
|
- lib/fontisan/utilities/brotli_wrapper.rb
|
|
647
642
|
- lib/fontisan/utilities/checksum_calculator.rb
|
data/docs/cli/audit.md
DELETED
|
@@ -1,337 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: audit
|
|
3
|
-
---
|
|
4
|
-
|
|
5
|
-
# audit
|
|
6
|
-
|
|
7
|
-
Produce a complete per-face font audit report — identity, style, metrics,
|
|
8
|
-
coverage, licensing, hinting, color capabilities, variable-font detail,
|
|
9
|
-
OpenType layout features, and Unicode/CLDR aggregation.
|
|
10
|
-
|
|
11
|
-
`audit` is the successor to `otfinfo`: it covers everything `otfinfo`
|
|
12
|
-
reports plus a great deal more (coverage, hinting, color, variation,
|
|
13
|
-
layout, language coverage), and supports collections, compare mode, and
|
|
14
|
-
whole-library summaries.
|
|
15
|
-
|
|
16
|
-
## Quick Reference
|
|
17
|
-
|
|
18
|
-
```bash
|
|
19
|
-
# One face
|
|
20
|
-
fontisan audit FONT.ttf
|
|
21
|
-
|
|
22
|
-
# Collection (one report per face)
|
|
23
|
-
fontisan audit COLLECTION.ttc
|
|
24
|
-
|
|
25
|
-
# Whole library
|
|
26
|
-
fontisan audit DIR/ --recursive --summary
|
|
27
|
-
|
|
28
|
-
# Compare two fonts or saved reports
|
|
29
|
-
fontisan audit --compare A.ttf B.ttf
|
|
30
|
-
```
|
|
31
|
-
|
|
32
|
-
## Variants
|
|
33
|
-
|
|
34
|
-
| Variant | What it does | Output |
|
|
35
|
-
|---------|-------------|--------|
|
|
36
|
-
| `audit FONT.ttf` | One AuditReport for the single face | `AuditReport` |
|
|
37
|
-
| `audit COLLECTION.ttc` | One AuditReport per face (in source order) | `Array<AuditReport>` |
|
|
38
|
-
| `audit DIR/ --recursive --summary` | Walk the directory, summarize the library | `LibrarySummary` |
|
|
39
|
-
| `audit --compare A B` | Diff two faces or two saved reports | `AuditDiff` |
|
|
40
|
-
|
|
41
|
-
## Options
|
|
42
|
-
|
|
43
|
-
| Option | Description |
|
|
44
|
-
|--------|-------------|
|
|
45
|
-
| `--format FORMAT` | Output format: `text` (default), `yaml`, `json` |
|
|
46
|
-
| `--output PATH`, `-o` | Write to a directory (collection/library), a file (single/compare), or stdout |
|
|
47
|
-
| `--font-index N` | Audit only face N of a collection (default: all) |
|
|
48
|
-
| `--brief` | Fast inventory — skip metrics/hinting/color/layout/UCD/CLDR |
|
|
49
|
-
| `--all-codepoints` | Include the full per-codepoint list (defaults to a compact range view) |
|
|
50
|
-
| `--ucd-version VER` | Aggregate against this UCD version (`latest` to probe) |
|
|
51
|
-
| `--with-language-coverage` | Compute CLDR language coverage % (auto-downloads CLDR on first use) |
|
|
52
|
-
| `--cldr-version VER` | CLDR version to use (`latest` to probe) |
|
|
53
|
-
| `--compare` | Diff two inputs (requires exactly two paths) |
|
|
54
|
-
| `--recursive` | Library mode: walk into subdirectories |
|
|
55
|
-
| `--summary` | Library mode: produce a `LibrarySummary` over a directory |
|
|
56
|
-
|
|
57
|
-
## Brief Mode
|
|
58
|
-
|
|
59
|
-
`--brief` runs only the cheap name-table extractors (provenance, identity,
|
|
60
|
-
style, licensing, coverage) and skips metrics, hinting, color,
|
|
61
|
-
variation, OpenType layout, UCD block/script aggregation, and CLDR
|
|
62
|
-
language coverage. Useful for taking a fast inventory of large libraries.
|
|
63
|
-
|
|
64
|
-
```bash
|
|
65
|
-
fontisan audit FONT.ttf --brief
|
|
66
|
-
fontisan audit DIR/ --recursive --summary --brief
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
Note: `audit --brief` is distinct from `info --brief`. `info --brief`
|
|
70
|
-
loads only 6 tables; `audit --brief` still loads the full font (Coverage
|
|
71
|
-
reads `cmap`) but selects a cheaper extractor subset.
|
|
72
|
-
|
|
73
|
-
## Single-Face Audit
|
|
74
|
-
|
|
75
|
-
```bash
|
|
76
|
-
# Text formatter (default)
|
|
77
|
-
fontisan audit FONT.ttf
|
|
78
|
-
|
|
79
|
-
# YAML (machine-readable)
|
|
80
|
-
fontisan audit FONT.ttf --format yaml
|
|
81
|
-
|
|
82
|
-
# JSON
|
|
83
|
-
fontisan audit FONT.ttf --format json | jq '.licensing'
|
|
84
|
-
|
|
85
|
-
# Write to disk
|
|
86
|
-
fontisan audit FONT.ttf -o report.yaml
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
Sample text output (truncated):
|
|
90
|
-
|
|
91
|
-
```
|
|
92
|
-
NotoSans-Regular
|
|
93
|
-
================================================================================
|
|
94
|
-
generated_at: 2026-06-24T18:11:39Z fontisan: 0.2.20
|
|
95
|
-
source_sha256: f5f552c8c5edb61fe6efb824baf4d4de47b1a8689ab4925ff43f7bd6a4ebece5
|
|
96
|
-
source_file: /path/to/NotoSans-Regular.ttf
|
|
97
|
-
source_format: ttf layout: single face (1/1)
|
|
98
|
-
|
|
99
|
-
IDENTITY
|
|
100
|
-
Family: Noto Sans
|
|
101
|
-
Subfamily: Regular
|
|
102
|
-
Full name: Noto Sans Regular
|
|
103
|
-
PostScript: NotoSans-Regular
|
|
104
|
-
Version: Version 2.015; ttfautohint (v1.8.4.7-5d5b)
|
|
105
|
-
Revision: 2.0149993896484375
|
|
106
|
-
|
|
107
|
-
STYLE
|
|
108
|
-
Weight class: 400 (Regular)
|
|
109
|
-
Width class: 5 (Medium)
|
|
110
|
-
Bold: no
|
|
111
|
-
Italic: no
|
|
112
|
-
PANOSE: 2 11 5 2 4 5 4 2 2 4
|
|
113
|
-
|
|
114
|
-
COVERAGE
|
|
115
|
-
Codepoints: 3094
|
|
116
|
-
Glyphs: 4515
|
|
117
|
-
cmap subtables: 4, 12
|
|
118
|
-
Ranges (top 10): U+0000-U+0000, U+000D-U+000D, U+0020-U+007E, ...
|
|
119
|
-
Unicode scripts: Latin, ...
|
|
120
|
-
|
|
121
|
-
LICENSING
|
|
122
|
-
License URL: https://scripts.sil.org/OFL
|
|
123
|
-
Embedding: 0x0000 (Editable embedding)
|
|
124
|
-
|
|
125
|
-
METRICS
|
|
126
|
-
Units per em: 1000
|
|
127
|
-
Ascender: 1160
|
|
128
|
-
Descender: -288
|
|
129
|
-
...
|
|
130
|
-
|
|
131
|
-
UNICODE BLOCKS
|
|
132
|
-
Basic Latin 95 / 128 74.2%
|
|
133
|
-
Latin-1 Supplement 96 / 128 75.0%
|
|
134
|
-
...
|
|
135
|
-
|
|
136
|
-
VARIABLE FONT
|
|
137
|
-
Axes: wght (100–900, default 400)
|
|
138
|
-
Named instances: 9
|
|
139
|
-
|
|
140
|
-
OPENTYPE LAYOUT
|
|
141
|
-
Scripts: latn, cyrl, grek, ...
|
|
142
|
-
Features: c2sc, calt, case, dlig, dnom, frac, kern, liga, ...
|
|
143
|
-
|
|
144
|
-
LANGUAGE COVERAGE
|
|
145
|
-
en: 99.2%
|
|
146
|
-
fr: 97.4%
|
|
147
|
-
...
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
## Collections
|
|
151
|
-
|
|
152
|
-
For TTC/OTC/dfont, one report is produced per face in source order.
|
|
153
|
-
|
|
154
|
-
```bash
|
|
155
|
-
# Audit every face
|
|
156
|
-
fontisan audit COLLECTION.ttc
|
|
157
|
-
|
|
158
|
-
# Audit only face 2
|
|
159
|
-
fontisan audit COLLECTION.ttc --font-index 2
|
|
160
|
-
|
|
161
|
-
# Write one file per face into a directory
|
|
162
|
-
fontisan audit COLLECTION.ttc -o reports/
|
|
163
|
-
|
|
164
|
-
# Resulting files use the postscript name with a 2-digit index prefix:
|
|
165
|
-
# 00-NotoSans-Regular.yaml
|
|
166
|
-
# 01-NotoSans-Bold.yaml
|
|
167
|
-
# 02-NotoSerif-Italic.yaml
|
|
168
|
-
```
|
|
169
|
-
|
|
170
|
-
## Compare Mode
|
|
171
|
-
|
|
172
|
-
`--compare` diffs two inputs. Each input is one of:
|
|
173
|
-
|
|
174
|
-
- A previously saved audit report (`.yaml` / `.yml` / `.json`)
|
|
175
|
-
- A font file (audited on-the-fly)
|
|
176
|
-
|
|
177
|
-
Mixed inputs are allowed — useful for tracking a font's evolution
|
|
178
|
-
against a checked-in baseline.
|
|
179
|
-
|
|
180
|
-
```bash
|
|
181
|
-
# Two live fonts
|
|
182
|
-
fontisan audit --compare a.ttf b.ttf
|
|
183
|
-
|
|
184
|
-
# Saved baseline vs. live
|
|
185
|
-
fontisan audit --compare baseline.yaml new.ttf
|
|
186
|
-
|
|
187
|
-
# Two saved reports
|
|
188
|
-
fontisan audit --compare v1.yaml v2.yaml -o diff.yaml
|
|
189
|
-
```
|
|
190
|
-
|
|
191
|
-
The output is an `AuditDiff` containing:
|
|
192
|
-
|
|
193
|
-
- `field_changes` — scalar field-level changes (e.g. weight_class 400 → 700)
|
|
194
|
-
- `codepoints` — added/removed/unchanged codepoint counts
|
|
195
|
-
- `added_features` / `removed_features`
|
|
196
|
-
- `added_scripts` / `removed_scripts`
|
|
197
|
-
- `added_blocks` / `removed_blocks`
|
|
198
|
-
- `added_languages` / `removed_languages`
|
|
199
|
-
|
|
200
|
-
## Library Mode
|
|
201
|
-
|
|
202
|
-
Point `audit` at a directory with `--recursive` and/or `--summary` to
|
|
203
|
-
scan a whole library of fonts.
|
|
204
|
-
|
|
205
|
-
```bash
|
|
206
|
-
# Flat directory
|
|
207
|
-
fontisan audit lib/ --summary
|
|
208
|
-
|
|
209
|
-
# Walk subdirectories
|
|
210
|
-
fontisan audit lib/ --recursive --summary
|
|
211
|
-
|
|
212
|
-
# YAML for downstream processing
|
|
213
|
-
fontisan audit lib/ --recursive --summary --format yaml -o library.yaml
|
|
214
|
-
```
|
|
215
|
-
|
|
216
|
-
The output is a `LibrarySummary` containing:
|
|
217
|
-
|
|
218
|
-
- `root_path`, `total_files`, `total_faces`, `scanned_extensions`
|
|
219
|
-
- `aggregate_metrics` — total codepoints/glyphs/bytes summed across faces
|
|
220
|
-
- `script_coverage` — per-script face counts and lists
|
|
221
|
-
- `duplicate_groups` — files grouped by `source_sha256` (size > 1)
|
|
222
|
-
- `license_distribution` — face counts per `license_url`
|
|
223
|
-
- `per_face_reports` — the full per-face reports used to aggregate
|
|
224
|
-
|
|
225
|
-
Files that fail to load (corrupt, unsupported) are listed on stderr as
|
|
226
|
-
`skipped <path>` and excluded from the summary.
|
|
227
|
-
|
|
228
|
-
## UCD Aggregation
|
|
229
|
-
|
|
230
|
-
By default, audit aggregates codepoints against the configured-default
|
|
231
|
-
UCD version, producing:
|
|
232
|
-
|
|
233
|
-
- `blocks` — per-Unicode-block coverage rows (name, range, total, covered, fill_ratio, complete)
|
|
234
|
-
- `unicode_scripts` — distinct scripts present in the font
|
|
235
|
-
|
|
236
|
-
Override with `--ucd-version`:
|
|
237
|
-
|
|
238
|
-
```bash
|
|
239
|
-
# Use a specific UCD version
|
|
240
|
-
fontisan audit FONT.ttf --ucd-version 16.0.0
|
|
241
|
-
|
|
242
|
-
# Probe and use the latest
|
|
243
|
-
fontisan audit FONT.ttf --ucd-version latest
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
Manage the local UCD cache with `fontisan ucd`:
|
|
247
|
-
|
|
248
|
-
```bash
|
|
249
|
-
fontisan ucd status
|
|
250
|
-
fontisan ucd list
|
|
251
|
-
fontisan ucd download 17.0.0
|
|
252
|
-
```
|
|
253
|
-
|
|
254
|
-
## CLDR Language Coverage
|
|
255
|
-
|
|
256
|
-
`--with-language-coverage` computes per-language coverage % using CLDR
|
|
257
|
-
exemplar sets. The first invocation downloads the CLDR data
|
|
258
|
-
(~MBs); subsequent invocations use the cache.
|
|
259
|
-
|
|
260
|
-
```bash
|
|
261
|
-
fontisan audit FONT.ttf --with-language-coverage
|
|
262
|
-
|
|
263
|
-
# Use a specific CLDR version
|
|
264
|
-
fontisan audit FONT.ttf --with-language-coverage --cldr-version 45
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
Manage the CLDR cache with `fontisan cldr`:
|
|
268
|
-
|
|
269
|
-
```bash
|
|
270
|
-
fontisan cldr status
|
|
271
|
-
fontisan cldr list
|
|
272
|
-
fontisan cldr download 45
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
## Ruby API
|
|
276
|
-
|
|
277
|
-
### Single face
|
|
278
|
-
|
|
279
|
-
```ruby
|
|
280
|
-
require "fontisan"
|
|
281
|
-
|
|
282
|
-
# Returns an AuditReport for a single font, or an Array<AuditReport>
|
|
283
|
-
# for a collection (one per face).
|
|
284
|
-
report = Fontisan::Commands::AuditCommand.new("font.ttf",
|
|
285
|
-
ucd_version: "17.0.0").run
|
|
286
|
-
|
|
287
|
-
puts report.family_name
|
|
288
|
-
puts report.total_codepoints
|
|
289
|
-
puts report.licensing.license_url
|
|
290
|
-
puts report.blocks.first.fill_ratio
|
|
291
|
-
```
|
|
292
|
-
|
|
293
|
-
### Compare
|
|
294
|
-
|
|
295
|
-
```ruby
|
|
296
|
-
diff = Fontisan::Commands::AuditCompareCommand.new(
|
|
297
|
-
"baseline.yaml", "new.ttf", ucd_version: "17.0.0"
|
|
298
|
-
).run
|
|
299
|
-
|
|
300
|
-
diff.field_changes.each { |c| puts "#{c.field}: #{c.left} → #{c.right}" }
|
|
301
|
-
puts "added codepoints: #{diff.codepoints.added_count}"
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
### Library summary
|
|
305
|
-
|
|
306
|
-
```ruby
|
|
307
|
-
cmd = Fontisan::Commands::AuditLibraryCommand.new(
|
|
308
|
-
"lib/", recursive: true, options: { ucd_version: "17.0.0" }
|
|
309
|
-
)
|
|
310
|
-
summary = cmd.run
|
|
311
|
-
cmd.skipped.each { |path| warn "skipped #{path}" }
|
|
312
|
-
|
|
313
|
-
summary.script_coverage.each do |row|
|
|
314
|
-
puts "#{row.script}: #{row.face_count} faces"
|
|
315
|
-
end
|
|
316
|
-
summary.duplicate_groups.each do |group|
|
|
317
|
-
puts "duplicate #{group.source_sha256[0,8]}: #{group.files.join(', ')}"
|
|
318
|
-
end
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
### Brief mode
|
|
322
|
-
|
|
323
|
-
```ruby
|
|
324
|
-
# Use the audit_brief: key (NOT brief:, which would trigger metadata-only
|
|
325
|
-
# font loading via BaseCommand).
|
|
326
|
-
report = Fontisan::Commands::AuditCommand.new(
|
|
327
|
-
"font.ttf", audit_brief: true, ucd_version: "17.0.0"
|
|
328
|
-
).run
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
## Related Commands
|
|
332
|
-
|
|
333
|
-
- [info](/cli/info) — Lighter-weight font metadata (replaces `otfinfo -i`)
|
|
334
|
-
- [tables](/cli/tables) — Raw OpenType table listing
|
|
335
|
-
- [features](/cli/features) — Just GSUB/GPOS features
|
|
336
|
-
- [scripts](/cli/scripts) — Just supported scripts
|
|
337
|
-
- [validate](/cli/validate) — Pass/fail quality checks (audit is descriptive; validate is prescriptive)
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Fontisan
|
|
4
|
-
module Cldr
|
|
5
|
-
# Produces audit-ready per-language coverage from a codepoint list
|
|
6
|
-
# and a Cldr::Index of per-language exemplar sets.
|
|
7
|
-
#
|
|
8
|
-
# Pure: no I/O, no side effects.
|
|
9
|
-
module Aggregator
|
|
10
|
-
module_function
|
|
11
|
-
|
|
12
|
-
# @param codepoints [Enumerable<Integer>] font's codepoints
|
|
13
|
-
# @param languages_index [Cldr::Index]
|
|
14
|
-
# @return [Array<Models::Cldr::LanguageCoverage>] sorted by
|
|
15
|
-
# descending coverage_ratio, then by language name
|
|
16
|
-
def aggregate(codepoints, languages_index)
|
|
17
|
-
font_set = Set.new(codepoints)
|
|
18
|
-
|
|
19
|
-
languages_index.entries.map do |lang, required_set|
|
|
20
|
-
covered = (font_set & required_set).size
|
|
21
|
-
total = required_set.size
|
|
22
|
-
Models::Cldr::LanguageCoverage.new(
|
|
23
|
-
language: lang,
|
|
24
|
-
covered: covered,
|
|
25
|
-
total: total,
|
|
26
|
-
coverage_ratio: total.zero? ? 0.0 : covered.fdiv(total).round(4),
|
|
27
|
-
fully_supported: total.positive? && covered == total,
|
|
28
|
-
)
|
|
29
|
-
end.sort_by { |lc| [lc.coverage_ratio * -1, lc.language] }
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
end
|
|
33
|
-
end
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "pathname"
|
|
4
|
-
|
|
5
|
-
module Fontisan
|
|
6
|
-
module Cldr
|
|
7
|
-
# Manages the on-disk CLDR cache layout.
|
|
8
|
-
#
|
|
9
|
-
# Cache root resolution honors `XDG_CONFIG_HOME` per the XDG Base
|
|
10
|
-
# Directory Specification. Falls back to `~/.config` on Unix.
|
|
11
|
-
#
|
|
12
|
-
# Layout:
|
|
13
|
-
#
|
|
14
|
-
# <root>/
|
|
15
|
-
# <version>/
|
|
16
|
-
# json/ # extracted CLDR JSON archive
|
|
17
|
-
# cldr-json/
|
|
18
|
-
# cldr-characters-full/
|
|
19
|
-
# main/<lang>/characters.json
|
|
20
|
-
# index/
|
|
21
|
-
# languages.yml # built index of per-language codepoint sets
|
|
22
|
-
#
|
|
23
|
-
# No network access — all methods are pure filesystem operations.
|
|
24
|
-
module CacheManager
|
|
25
|
-
LANGUAGES_INDEX_FILENAME = "languages.yml"
|
|
26
|
-
private_constant :LANGUAGES_INDEX_FILENAME
|
|
27
|
-
|
|
28
|
-
class << self
|
|
29
|
-
# Root path of the CLDR cache.
|
|
30
|
-
# @return [Pathname]
|
|
31
|
-
def root
|
|
32
|
-
base = xdg_config_home || File.join(Dir.home, ".config")
|
|
33
|
-
Pathname.new(base).join("fontisan", "cldr")
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
# Per-version directory.
|
|
37
|
-
# @param version [String] e.g. "46.0.0"
|
|
38
|
-
# @return [Pathname]
|
|
39
|
-
def version_dir(version)
|
|
40
|
-
root.join(version)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
# Directory where the raw CLDR JSON archive is extracted.
|
|
44
|
-
# @param version [String]
|
|
45
|
-
# @return [Pathname]
|
|
46
|
-
def json_dir(version)
|
|
47
|
-
version_dir(version).join("json")
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Directory containing the per-language characters.json files
|
|
51
|
-
# inside the extracted archive.
|
|
52
|
-
# @param version [String]
|
|
53
|
-
# @return [Pathname]
|
|
54
|
-
def characters_main_dir(version)
|
|
55
|
-
json_dir(version).join("cldr-json", "cldr-characters-full", "main")
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
# Directory holding the derived language index for a version.
|
|
59
|
-
# @param version [String]
|
|
60
|
-
# @return [Pathname]
|
|
61
|
-
def index_dir(version)
|
|
62
|
-
version_dir(version).join("index")
|
|
63
|
-
end
|
|
64
|
-
|
|
65
|
-
def languages_index_path(version)
|
|
66
|
-
index_dir(version).join(LANGUAGES_INDEX_FILENAME)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
# True if the extracted JSON archive is present for this version.
|
|
70
|
-
# @param version [String]
|
|
71
|
-
# @return [Boolean]
|
|
72
|
-
def cached?(version)
|
|
73
|
-
characters_main_dir(version).exist?
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
# All versions currently in the cache (sorted ascending).
|
|
77
|
-
# @return [Array<String>]
|
|
78
|
-
def cached_versions
|
|
79
|
-
return [] unless root.exist?
|
|
80
|
-
|
|
81
|
-
root.children.select(&:directory?).map { |p| p.basename.to_s }.sort
|
|
82
|
-
end
|
|
83
|
-
|
|
84
|
-
# Create the version directory and json/index subdirs.
|
|
85
|
-
# Idempotent.
|
|
86
|
-
# @param version [String]
|
|
87
|
-
def ensure_version_dir!(version)
|
|
88
|
-
json_dir(version).mkpath
|
|
89
|
-
index_dir(version).mkpath
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
# Remove a version from the cache. No-op if absent.
|
|
93
|
-
# @param version [String]
|
|
94
|
-
def remove_version(version)
|
|
95
|
-
dir = version_dir(version)
|
|
96
|
-
dir.rmtree if dir.exist?
|
|
97
|
-
end
|
|
98
|
-
|
|
99
|
-
private
|
|
100
|
-
|
|
101
|
-
def xdg_config_home
|
|
102
|
-
env = ENV["XDG_CONFIG_HOME"]
|
|
103
|
-
return nil if env.nil? || env.empty?
|
|
104
|
-
|
|
105
|
-
env
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
end
|
|
109
|
-
end
|
|
110
|
-
end
|
data/lib/fontisan/cldr/config.rb
DELETED
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "yaml"
|
|
4
|
-
|
|
5
|
-
module Fontisan
|
|
6
|
-
module Cldr
|
|
7
|
-
# Single source of truth for CLDR version selection.
|
|
8
|
-
#
|
|
9
|
-
# Wraps `lib/fontisan/config/cldr.yml`. Loads the YAML once at first
|
|
10
|
-
# access and memoizes. All other Cldr::* classes resolve versions,
|
|
11
|
-
# URLs, and known-version validation through this module.
|
|
12
|
-
module Config
|
|
13
|
-
CONFIG_PATH = File.expand_path("../config/cldr.yml", __dir__)
|
|
14
|
-
private_constant :CONFIG_PATH
|
|
15
|
-
|
|
16
|
-
class << self
|
|
17
|
-
# The CLDR version Fontisan uses by default for auto-download and
|
|
18
|
-
# `fontisan cldr download` (no args). String like "46.0.0".
|
|
19
|
-
def default_version
|
|
20
|
-
data[:default_version]
|
|
21
|
-
end
|
|
22
|
-
|
|
23
|
-
# Array of CLDR version strings this Fontisan release recognizes.
|
|
24
|
-
# Used by VersionResolver to reject unknown versions early.
|
|
25
|
-
def known_versions
|
|
26
|
-
data[:known_versions]
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Base URL for fetching CLDR JSON artifacts.
|
|
30
|
-
def base_url
|
|
31
|
-
data[:base_url]
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
# Listing URL for `--latest` probing.
|
|
35
|
-
def listing_url
|
|
36
|
-
data[:listing_url]
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
# Full URL to the CLDR JSON full archive for a version.
|
|
40
|
-
# @param version [String] e.g. "46.0.0"
|
|
41
|
-
# @return [String]
|
|
42
|
-
def archive_url_for(version)
|
|
43
|
-
"#{base_url}/#{version}/cldr-#{version}-json-full.zip"
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# True if the version appears in `known_versions`.
|
|
47
|
-
def known?(version)
|
|
48
|
-
known_versions.include?(version)
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
private
|
|
52
|
-
|
|
53
|
-
def data
|
|
54
|
-
@data ||= YAML.load_file(CONFIG_PATH).transform_keys(&:to_sym)
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|