fontisan 0.2.22 → 0.2.23

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 (88) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +6 -0
  3. data/.rubocop_todo.yml +93 -17
  4. data/CHANGELOG.md +12 -2
  5. data/README.adoc +6 -210
  6. data/fontisan.gemspec +48 -0
  7. data/lib/fontisan/cldr/unicode_set_parser.rb +23 -6
  8. data/lib/fontisan/cldr/version_resolver.rb +1 -1
  9. data/lib/fontisan/cli.rb +0 -170
  10. data/lib/fontisan/commands.rb +0 -3
  11. data/lib/fontisan/formatters/text_formatter.rb +0 -6
  12. data/lib/fontisan/formatters.rb +0 -3
  13. data/lib/fontisan/hints.rb +6 -3
  14. data/lib/fontisan/models.rb +4 -4
  15. data/lib/fontisan/pipeline/strategies.rb +4 -2
  16. data/lib/fontisan/pipeline.rb +2 -1
  17. data/lib/fontisan/tables/cff.rb +2 -1
  18. data/lib/fontisan/tables.rb +2 -1
  19. data/lib/fontisan/version.rb +1 -1
  20. data/lib/fontisan.rb +0 -3
  21. metadata +7 -70
  22. data/lib/fontisan/audit/codepoint_range_coalescer.rb +0 -41
  23. data/lib/fontisan/audit/context.rb +0 -122
  24. data/lib/fontisan/audit/differ.rb +0 -124
  25. data/lib/fontisan/audit/extractors/aggregations.rb +0 -54
  26. data/lib/fontisan/audit/extractors/base.rb +0 -26
  27. data/lib/fontisan/audit/extractors/color_capabilities.rb +0 -141
  28. data/lib/fontisan/audit/extractors/coverage.rb +0 -48
  29. data/lib/fontisan/audit/extractors/hinting.rb +0 -197
  30. data/lib/fontisan/audit/extractors/identity.rb +0 -52
  31. data/lib/fontisan/audit/extractors/language_coverage.rb +0 -37
  32. data/lib/fontisan/audit/extractors/licensing.rb +0 -79
  33. data/lib/fontisan/audit/extractors/metrics.rb +0 -103
  34. data/lib/fontisan/audit/extractors/opentype_layout.rb +0 -69
  35. data/lib/fontisan/audit/extractors/provenance.rb +0 -29
  36. data/lib/fontisan/audit/extractors/style.rb +0 -32
  37. data/lib/fontisan/audit/extractors/variation_detail.rb +0 -99
  38. data/lib/fontisan/audit/extractors.rb +0 -27
  39. data/lib/fontisan/audit/library_aggregator.rb +0 -83
  40. data/lib/fontisan/audit/library_auditor.rb +0 -90
  41. data/lib/fontisan/audit/registry.rb +0 -60
  42. data/lib/fontisan/audit/style_extractor.rb +0 -80
  43. data/lib/fontisan/audit.rb +0 -20
  44. data/lib/fontisan/cli/ucd_cli.rb +0 -97
  45. data/lib/fontisan/commands/audit_command.rb +0 -123
  46. data/lib/fontisan/commands/audit_compare_command.rb +0 -66
  47. data/lib/fontisan/commands/audit_library_command.rb +0 -46
  48. data/lib/fontisan/config/ucd.yml +0 -23
  49. data/lib/fontisan/formatters/audit_diff_text_renderer.rb +0 -122
  50. data/lib/fontisan/formatters/audit_text_renderer.rb +0 -324
  51. data/lib/fontisan/formatters/library_summary_text_renderer.rb +0 -99
  52. data/lib/fontisan/models/audit/audit_axis.rb +0 -30
  53. data/lib/fontisan/models/audit/audit_block.rb +0 -32
  54. data/lib/fontisan/models/audit/audit_diff.rb +0 -77
  55. data/lib/fontisan/models/audit/audit_report.rb +0 -153
  56. data/lib/fontisan/models/audit/codepoint_range.rb +0 -40
  57. data/lib/fontisan/models/audit/codepoint_set_diff.rb +0 -34
  58. data/lib/fontisan/models/audit/color_capabilities.rb +0 -93
  59. data/lib/fontisan/models/audit/duplicate_group.rb +0 -23
  60. data/lib/fontisan/models/audit/embedding_type.rb +0 -76
  61. data/lib/fontisan/models/audit/field_change.rb +0 -28
  62. data/lib/fontisan/models/audit/fs_selection_flags.rb +0 -61
  63. data/lib/fontisan/models/audit/gasp_range.rb +0 -63
  64. data/lib/fontisan/models/audit/hinting.rb +0 -93
  65. data/lib/fontisan/models/audit/library_summary.rb +0 -40
  66. data/lib/fontisan/models/audit/licensing.rb +0 -48
  67. data/lib/fontisan/models/audit/metrics.rb +0 -111
  68. data/lib/fontisan/models/audit/named_instance.rb +0 -41
  69. data/lib/fontisan/models/audit/opentype_layout.rb +0 -40
  70. data/lib/fontisan/models/audit/script_coverage_row.rb +0 -26
  71. data/lib/fontisan/models/audit/script_features.rb +0 -28
  72. data/lib/fontisan/models/audit/variation_detail.rb +0 -44
  73. data/lib/fontisan/models/audit.rb +0 -33
  74. data/lib/fontisan/models/ucd/ucd.rb +0 -38
  75. data/lib/fontisan/models/ucd/ucd_char.rb +0 -67
  76. data/lib/fontisan/models/ucd.rb +0 -19
  77. data/lib/fontisan/ucd/aggregator.rb +0 -73
  78. data/lib/fontisan/ucd/cache_manager.rb +0 -111
  79. data/lib/fontisan/ucd/config.rb +0 -59
  80. data/lib/fontisan/ucd/download_error.rb +0 -9
  81. data/lib/fontisan/ucd/downloader.rb +0 -88
  82. data/lib/fontisan/ucd/error.rb +0 -8
  83. data/lib/fontisan/ucd/index.rb +0 -103
  84. data/lib/fontisan/ucd/index_builder.rb +0 -107
  85. data/lib/fontisan/ucd/range_entry.rb +0 -56
  86. data/lib/fontisan/ucd/unknown_version_error.rb +0 -9
  87. data/lib/fontisan/ucd/version_resolver.rb +0 -79
  88. data/lib/fontisan/ucd.rb +0 -23
data/lib/fontisan/cli.rb CHANGED
@@ -25,93 +25,9 @@ module Fontisan
25
25
  desc: "Suppress non-error output",
26
26
  aliases: "-q"
27
27
 
28
- desc "ucd", "Manage local UCD cache (subcommands)", hide: true
29
- subcommand "ucd", UcdCli
30
-
31
28
  desc "cldr", "Manage local CLDR cache (subcommands)", hide: true
32
29
  subcommand "cldr", CldrCli
33
30
 
34
- desc "audit PATH", "Produce a per-face font audit report, or diff/summarize"
35
- long_desc <<~DESC
36
- Produce a complete per-face font audit report covering identity, style,
37
- metrics, coverage (Unicode blocks/scripts), licensing, hinting, color
38
- capabilities, variable font detail, and OpenType layout features.
39
-
40
- For TTC/OTC/dfont collections, one report per face is produced. Use
41
- --output to write reports to disk; --font-index to audit a single face.
42
-
43
- Variants:
44
- fontisan audit FONT.ttf
45
- fontisan audit COLLECTION.ttc
46
- fontisan audit DIR/ --recursive --summary
47
- fontisan audit --compare A.ttf B.ttf
48
- fontisan audit --compare A.yaml B.yaml
49
-
50
- Output formats: text (default), yaml, json.
51
-
52
- Use --brief for a fast inventory pass that skips metrics, hinting,
53
- color, variable-font detail, OpenType layout, and UCD/CLDR
54
- aggregation — only identity, style, licensing, and codepoint coverage.
55
- DESC
56
- option :font_index, type: :numeric,
57
- desc: "Audit only this face in a collection (default: all)"
58
- option :all_codepoints, type: :boolean, default: false,
59
- desc: "Include the full per-codepoint list " \
60
- "(defaults to compact range view)"
61
- option :ucd_version, type: :string,
62
- desc: "UCD version to aggregate against " \
63
- "(default: configured default; 'latest' to probe)"
64
- option :with_language_coverage, type: :boolean, default: false,
65
- desc: "Compute coverage % per CLDR language " \
66
- "(requires CLDR cache; auto-downloads)"
67
- option :cldr_version, type: :string,
68
- desc: "CLDR version (default: configured default; " \
69
- "'latest' to probe)"
70
- option :brief, type: :boolean, default: false,
71
- desc: "Skip metrics/hinting/color/layout/UCD/CLDR for a " \
72
- "fast inventory pass"
73
- option :compare, type: :boolean, default: false,
74
- desc: "Diff two fonts or two saved reports " \
75
- "(requires exactly two PATHs)"
76
- option :recursive, type: :boolean, default: false,
77
- desc: "Audit every font under a directory tree " \
78
- "(library mode)"
79
- option :summary, type: :boolean, default: false,
80
- desc: "Produce a LibrarySummary over a directory of fonts"
81
- option :output, type: :string,
82
- desc: "Output directory (collections/library) or file " \
83
- "(single font / compare)",
84
- aliases: "-o"
85
- # Produce a complete font audit report, or diff two fonts/reports,
86
- # or summarize a whole library.
87
- #
88
- # @param paths [Array<String>] one path (audit/library), or two paths (--compare)
89
- def audit(*paths)
90
- raise Thor::Error, "audit requires one PATH (or two with --compare)" if paths.empty?
91
-
92
- if options[:compare]
93
- unless paths.length == 2
94
- raise Thor::Error,
95
- "audit --compare requires exactly two paths"
96
- end
97
-
98
- return run_compare(paths[0], paths[1])
99
- end
100
-
101
- raise Thor::Error, "audit requires exactly one PATH" unless paths.length == 1
102
-
103
- path = paths[0]
104
- if Dir.exist?(path) && !library_mode?(path)
105
- raise Thor::Error,
106
- "audit on a directory requires --recursive or --summary"
107
- end
108
- return run_library_audit(path) if library_mode?(path)
109
-
110
- run_single_audit(path)
111
- rescue Errno::ENOENT, Error, Thor::Error => e
112
- handle_error(e)
113
- end
114
-
115
31
  desc "info PATH", "Display font information"
116
32
  option :brief, type: :boolean, default: false,
117
33
  desc: "Brief mode - only essential info (5x faster, uses metadata loading)",
@@ -788,92 +704,6 @@ module Fontisan
788
704
  puts output unless options[:quiet]
789
705
  end
790
706
 
791
- # Write audit reports to disk. If `target` is a directory (or there are
792
- # multiple reports), one file per face is written under it. If `target`
793
- # is a file path and there's exactly one report, that exact path is used.
794
- #
795
- # @param reports [Array<Models::Audit::AuditReport>]
796
- # @param target [String] directory (collection) or file path (single)
797
- # @param format [String] "yaml" or "json"
798
- # @return [void]
799
- def write_audit_outputs(reports, target, format)
800
- sym_format = format.to_sym
801
-
802
- if reports.one? && !Dir.exist?(target) && File.extname(target) != ""
803
- File.write(target, serialize_report(reports.first, sym_format))
804
- puts "Wrote #{target}" unless options[:quiet]
805
- return
806
- end
807
-
808
- paths = Commands::AuditCommand.write_reports(reports, to: target,
809
- format: sym_format)
810
- paths.each { |p| puts "Wrote #{p}" unless options[:quiet] }
811
- end
812
-
813
- def run_single_audit(path)
814
- cmd_options = options.dup
815
- cmd_options.delete(:output)
816
- # Audit's --brief selects a cheap extractor subset but still needs FULL
817
- # font loading (Coverage reads cmap). Translate to :audit_brief so
818
- # BaseCommand's :brief → METADATA shortcut does not fire.
819
- cmd_options[:audit_brief] = cmd_options.delete(:brief) if cmd_options.key?(:brief)
820
- command = Commands::AuditCommand.new(path, cmd_options)
821
- reports = Array(command.run)
822
-
823
- if options[:output]
824
- write_audit_outputs(reports, options[:output], options[:format])
825
- else
826
- reports.each { |r| output_result(r) }
827
- end
828
- end
829
-
830
- def run_compare(left_path, right_path)
831
- cmd = Commands::AuditCompareCommand.new(left_path, right_path, options)
832
- diff = cmd.run
833
- return if options[:quiet]
834
-
835
- if options[:output]
836
- File.write(options[:output], serialize_report(diff, options[:format].to_sym))
837
- puts "Wrote #{options[:output]}"
838
- return
839
- end
840
-
841
- output_result(diff)
842
- end
843
-
844
- def run_library_audit(path)
845
- cmd = Commands::AuditLibraryCommand.new(
846
- path,
847
- recursive: options[:recursive],
848
- options: options.dup,
849
- )
850
- summary = cmd.run
851
- announce_skipped(cmd.skipped)
852
- return if options[:quiet]
853
-
854
- if options[:output]
855
- File.write(options[:output],
856
- serialize_report(summary, options[:format].to_sym))
857
- puts "Wrote #{options[:output]}"
858
- return
859
- end
860
-
861
- output_result(summary)
862
- end
863
-
864
- # Library mode triggers when the path is a directory and either
865
- # --recursive or --summary is requested. A single-file audit ignores
866
- # both flags (a TTC is audited face-by-face via run_single_audit).
867
- def library_mode?(path)
868
- Dir.exist?(path) && (options[:recursive] || options[:summary])
869
- end
870
-
871
- def announce_skipped(skipped)
872
- return if skipped.empty?
873
-
874
- skipped.each { |p| warn "skipped #{p}" }
875
- end
876
-
877
707
  def serialize_report(report, format)
878
708
  format == :json ? report.to_json : report.to_yaml
879
709
  end
@@ -4,9 +4,6 @@
4
4
 
5
5
  module Fontisan
6
6
  module Commands
7
- autoload :AuditCompareCommand, "fontisan/commands/audit_compare_command"
8
- autoload :AuditCommand, "fontisan/commands/audit_command"
9
- autoload :AuditLibraryCommand, "fontisan/commands/audit_library_command"
10
7
  autoload :BaseCommand, "fontisan/commands/base_command"
11
8
  autoload :ConvertCommand, "fontisan/commands/convert_command"
12
9
  autoload :DumpTableCommand, "fontisan/commands/dump_table_command"
@@ -44,12 +44,6 @@ module Fontisan
44
44
  format_collection_info(model)
45
45
  when Models::CollectionBriefInfo
46
46
  format_collection_brief_info(model)
47
- when Models::Audit::AuditReport
48
- Formatters::AuditTextRenderer.new(model).render
49
- when Models::Audit::AuditDiff
50
- Formatters::AuditDiffTextRenderer.new(model).render
51
- when Models::Audit::LibrarySummary
52
- Formatters::LibrarySummaryTextRenderer.new(model).render
53
47
  else
54
48
  model.to_s
55
49
  end
@@ -4,9 +4,6 @@
4
4
 
5
5
  module Fontisan
6
6
  module Formatters
7
- autoload :AuditDiffTextRenderer, "fontisan/formatters/audit_diff_text_renderer"
8
- autoload :AuditTextRenderer, "fontisan/formatters/audit_text_renderer"
9
- autoload :LibrarySummaryTextRenderer, "fontisan/formatters/library_summary_text_renderer"
10
7
  autoload :TextFormatter, "fontisan/formatters/text_formatter"
11
8
  end
12
9
  end
@@ -7,10 +7,13 @@ module Fontisan
7
7
  autoload :HintConverter, "fontisan/hints/hint_converter"
8
8
  autoload :HintValidator, "fontisan/hints/hint_validator"
9
9
  autoload :PostScriptHintApplier, "fontisan/hints/postscript_hint_applier"
10
- autoload :PostScriptHintExtractor, "fontisan/hints/postscript_hint_extractor"
10
+ autoload :PostScriptHintExtractor,
11
+ "fontisan/hints/postscript_hint_extractor"
11
12
  autoload :TrueTypeHintApplier, "fontisan/hints/truetype_hint_applier"
12
13
  autoload :TrueTypeHintExtractor, "fontisan/hints/truetype_hint_extractor"
13
- autoload :TrueTypeInstructionAnalyzer, "fontisan/hints/truetype_instruction_analyzer"
14
- autoload :TrueTypeInstructionGenerator, "fontisan/hints/truetype_instruction_generator"
14
+ autoload :TrueTypeInstructionAnalyzer,
15
+ "fontisan/hints/truetype_instruction_analyzer"
16
+ autoload :TrueTypeInstructionGenerator,
17
+ "fontisan/hints/truetype_instruction_generator"
15
18
  end
16
19
  end
@@ -4,8 +4,8 @@
4
4
 
5
5
  module Fontisan
6
6
  module Models
7
- autoload :AllScriptsFeaturesInfo, "fontisan/models/all_scripts_features_info"
8
- autoload :Audit, "fontisan/models/audit"
7
+ autoload :AllScriptsFeaturesInfo,
8
+ "fontisan/models/all_scripts_features_info"
9
9
  autoload :AxisInfo, "fontisan/models/variable_font_info"
10
10
  autoload :BitmapGlyph, "fontisan/models/bitmap_glyph"
11
11
  autoload :BitmapStrike, "fontisan/models/bitmap_strike"
@@ -13,7 +13,8 @@ module Fontisan
13
13
  autoload :CollectionFontSummary, "fontisan/models/collection_font_summary"
14
14
  autoload :CollectionInfo, "fontisan/models/collection_info"
15
15
  autoload :CollectionListInfo, "fontisan/models/collection_list_info"
16
- autoload :CollectionValidationReport, "fontisan/models/collection_validation_report"
16
+ autoload :CollectionValidationReport,
17
+ "fontisan/models/collection_validation_report"
17
18
  autoload :Cldr, "fontisan/models/cldr"
18
19
  autoload :ColorGlyph, "fontisan/models/color_glyph"
19
20
  autoload :ColorLayer, "fontisan/models/color_layer"
@@ -38,7 +39,6 @@ module Fontisan
38
39
  autoload :TableInfo, "fontisan/models/table_info"
39
40
  autoload :TableSharingInfo, "fontisan/models/table_sharing_info"
40
41
  autoload :Ttx, "fontisan/models/ttx/ttfont"
41
- autoload :Ucd, "fontisan/models/ucd"
42
42
  autoload :UnicodeMapping, "fontisan/models/unicode_mappings"
43
43
  autoload :UnicodeMappings, "fontisan/models/unicode_mappings"
44
44
  autoload :ValidationReport, "fontisan/models/validation_report"
@@ -6,9 +6,11 @@ module Fontisan
6
6
  module Pipeline
7
7
  module Strategies
8
8
  autoload :BaseStrategy, "fontisan/pipeline/strategies/base_strategy"
9
- autoload :InstanceStrategy, "fontisan/pipeline/strategies/instance_strategy"
9
+ autoload :InstanceStrategy,
10
+ "fontisan/pipeline/strategies/instance_strategy"
10
11
  autoload :NamedStrategy, "fontisan/pipeline/strategies/named_strategy"
11
- autoload :PreserveStrategy, "fontisan/pipeline/strategies/preserve_strategy"
12
+ autoload :PreserveStrategy,
13
+ "fontisan/pipeline/strategies/preserve_strategy"
12
14
  end
13
15
  end
14
16
  end
@@ -7,7 +7,8 @@ module Fontisan
7
7
  autoload :FormatDetector, "fontisan/pipeline/format_detector"
8
8
  autoload :OutputWriter, "fontisan/pipeline/output_writer"
9
9
  autoload :Strategies, "fontisan/pipeline/strategies/base_strategy"
10
- autoload :TransformationPipeline, "fontisan/pipeline/transformation_pipeline"
10
+ autoload :TransformationPipeline,
11
+ "fontisan/pipeline/transformation_pipeline"
11
12
  autoload :VariationResolver, "fontisan/pipeline/variation_resolver"
12
13
  end
13
14
  end
@@ -54,7 +54,8 @@ module Fontisan
54
54
  autoload :DictBuilder, "fontisan/tables/cff/dict_builder"
55
55
  autoload :Encoding, "fontisan/tables/cff/encoding"
56
56
  autoload :Header, "fontisan/tables/cff/header"
57
- autoload :HintOperationInjector, "fontisan/tables/cff/hint_operation_injector"
57
+ autoload :HintOperationInjector,
58
+ "fontisan/tables/cff/hint_operation_injector"
58
59
  autoload :Index, "fontisan/tables/cff/index"
59
60
  autoload :IndexBuilder, "fontisan/tables/cff/index_builder"
60
61
  autoload :OffsetRecalculator, "fontisan/tables/cff/offset_recalculator"
@@ -12,7 +12,8 @@ module Fontisan
12
12
  autoload :CmapTable, "fontisan/tables/cmap_table"
13
13
  autoload :Colr, "fontisan/tables/colr"
14
14
  autoload :CompoundGlyph, "fontisan/tables/glyf/compound_glyph"
15
- autoload :CompoundGlyphResolver, "fontisan/tables/glyf/compound_glyph_resolver"
15
+ autoload :CompoundGlyphResolver,
16
+ "fontisan/tables/glyf/compound_glyph_resolver"
16
17
  autoload :Cpal, "fontisan/tables/cpal"
17
18
  autoload :CurveConverter, "fontisan/tables/glyf/curve_converter"
18
19
  autoload :Cvar, "fontisan/tables/cvar"
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Fontisan
4
- VERSION = "0.2.22"
4
+ VERSION = "0.2.23"
5
5
  end
data/lib/fontisan.rb CHANGED
@@ -72,7 +72,6 @@ module Fontisan
72
72
  autoload :VariationDataCorruptedError, "fontisan/error"
73
73
 
74
74
  # Namespace hubs (each hub declares its own child autoloads)
75
- autoload :Audit, "fontisan/audit"
76
75
  autoload :Binary, "fontisan/binary"
77
76
  autoload :Cldr, "fontisan/cldr"
78
77
  autoload :Collection, "fontisan/collection"
@@ -89,7 +88,6 @@ module Fontisan
89
88
  autoload :Svg, "fontisan/svg"
90
89
  autoload :Tables, "fontisan/tables"
91
90
  autoload :Type1, "fontisan/type1"
92
- autoload :Ucd, "fontisan/ucd"
93
91
  autoload :Utilities, "fontisan/utilities"
94
92
  autoload :Utils, "fontisan/utils"
95
93
  autoload :Validation, "fontisan/validation"
@@ -116,7 +114,6 @@ module Fontisan
116
114
  autoload :TrueTypeFont, "fontisan/true_type_font"
117
115
  autoload :TrueTypeFontExtensions, "fontisan/true_type_font_extensions"
118
116
  autoload :Type1Font, "fontisan/type1_font"
119
- autoload :UcdCli, "fontisan/cli/ucd_cli"
120
117
  autoload :CldrCli, "fontisan/cli/cldr_cli"
121
118
  autoload :Woff2Font, "fontisan/woff2_font"
122
119
  autoload :WoffFont, "fontisan/woff_font"
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fontisan
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.22
4
+ version: 0.2.23
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
+ autorequire:
8
9
  bindir: exe
9
10
  cert_chain: []
10
- date: 1980-01-02 00:00:00.000000000 Z
11
+ date: 2026-06-29 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: base64
@@ -262,29 +263,8 @@ files:
262
263
  - docs/public/web-app-manifest-512x512.png
263
264
  - docs/scripts/post-build.mjs
264
265
  - exe/fontisan
266
+ - fontisan.gemspec
265
267
  - lib/fontisan.rb
266
- - lib/fontisan/audit.rb
267
- - lib/fontisan/audit/codepoint_range_coalescer.rb
268
- - lib/fontisan/audit/context.rb
269
- - lib/fontisan/audit/differ.rb
270
- - lib/fontisan/audit/extractors.rb
271
- - lib/fontisan/audit/extractors/aggregations.rb
272
- - lib/fontisan/audit/extractors/base.rb
273
- - lib/fontisan/audit/extractors/color_capabilities.rb
274
- - lib/fontisan/audit/extractors/coverage.rb
275
- - lib/fontisan/audit/extractors/hinting.rb
276
- - lib/fontisan/audit/extractors/identity.rb
277
- - lib/fontisan/audit/extractors/language_coverage.rb
278
- - lib/fontisan/audit/extractors/licensing.rb
279
- - lib/fontisan/audit/extractors/metrics.rb
280
- - lib/fontisan/audit/extractors/opentype_layout.rb
281
- - lib/fontisan/audit/extractors/provenance.rb
282
- - lib/fontisan/audit/extractors/style.rb
283
- - lib/fontisan/audit/extractors/variation_detail.rb
284
- - lib/fontisan/audit/library_aggregator.rb
285
- - lib/fontisan/audit/library_auditor.rb
286
- - lib/fontisan/audit/registry.rb
287
- - lib/fontisan/audit/style_extractor.rb
288
268
  - lib/fontisan/base_collection.rb
289
269
  - lib/fontisan/binary.rb
290
270
  - lib/fontisan/binary/base_record.rb
@@ -303,7 +283,6 @@ files:
303
283
  - lib/fontisan/cldr/version_resolver.rb
304
284
  - lib/fontisan/cli.rb
305
285
  - lib/fontisan/cli/cldr_cli.rb
306
- - lib/fontisan/cli/ucd_cli.rb
307
286
  - lib/fontisan/collection.rb
308
287
  - lib/fontisan/collection/builder.rb
309
288
  - lib/fontisan/collection/dfont_builder.rb
@@ -313,9 +292,6 @@ files:
313
292
  - lib/fontisan/collection/table_deduplicator.rb
314
293
  - lib/fontisan/collection/writer.rb
315
294
  - lib/fontisan/commands.rb
316
- - lib/fontisan/commands/audit_command.rb
317
- - lib/fontisan/commands/audit_compare_command.rb
318
- - lib/fontisan/commands/audit_library_command.rb
319
295
  - lib/fontisan/commands/base_command.rb
320
296
  - lib/fontisan/commands/convert_command.rb
321
297
  - lib/fontisan/commands/dump_table_command.rb
@@ -342,7 +318,6 @@ files:
342
318
  - lib/fontisan/config/scripts.yml
343
319
  - lib/fontisan/config/subset_profiles.yml
344
320
  - lib/fontisan/config/svg_settings.yml
345
- - lib/fontisan/config/ucd.yml
346
321
  - lib/fontisan/config/variable_settings.yml
347
322
  - lib/fontisan/config/woff2_settings.yml
348
323
  - lib/fontisan/constants.rb
@@ -379,9 +354,6 @@ files:
379
354
  - lib/fontisan/font_loader.rb
380
355
  - lib/fontisan/font_writer.rb
381
356
  - lib/fontisan/formatters.rb
382
- - lib/fontisan/formatters/audit_diff_text_renderer.rb
383
- - lib/fontisan/formatters/audit_text_renderer.rb
384
- - lib/fontisan/formatters/library_summary_text_renderer.rb
385
357
  - lib/fontisan/formatters/text_formatter.rb
386
358
  - lib/fontisan/glyph_accessor.rb
387
359
  - lib/fontisan/hints.rb
@@ -397,28 +369,6 @@ files:
397
369
  - lib/fontisan/metrics_calculator.rb
398
370
  - lib/fontisan/models.rb
399
371
  - lib/fontisan/models/all_scripts_features_info.rb
400
- - lib/fontisan/models/audit.rb
401
- - lib/fontisan/models/audit/audit_axis.rb
402
- - lib/fontisan/models/audit/audit_block.rb
403
- - lib/fontisan/models/audit/audit_diff.rb
404
- - lib/fontisan/models/audit/audit_report.rb
405
- - lib/fontisan/models/audit/codepoint_range.rb
406
- - lib/fontisan/models/audit/codepoint_set_diff.rb
407
- - lib/fontisan/models/audit/color_capabilities.rb
408
- - lib/fontisan/models/audit/duplicate_group.rb
409
- - lib/fontisan/models/audit/embedding_type.rb
410
- - lib/fontisan/models/audit/field_change.rb
411
- - lib/fontisan/models/audit/fs_selection_flags.rb
412
- - lib/fontisan/models/audit/gasp_range.rb
413
- - lib/fontisan/models/audit/hinting.rb
414
- - lib/fontisan/models/audit/library_summary.rb
415
- - lib/fontisan/models/audit/licensing.rb
416
- - lib/fontisan/models/audit/metrics.rb
417
- - lib/fontisan/models/audit/named_instance.rb
418
- - lib/fontisan/models/audit/opentype_layout.rb
419
- - lib/fontisan/models/audit/script_coverage_row.rb
420
- - lib/fontisan/models/audit/script_features.rb
421
- - lib/fontisan/models/audit/variation_detail.rb
422
372
  - lib/fontisan/models/bitmap_glyph.rb
423
373
  - lib/fontisan/models/bitmap_strike.rb
424
374
  - lib/fontisan/models/cldr.rb
@@ -456,9 +406,6 @@ files:
456
406
  - lib/fontisan/models/ttx/tables/os2_table.rb
457
407
  - lib/fontisan/models/ttx/tables/post_table.rb
458
408
  - lib/fontisan/models/ttx/ttfont.rb
459
- - lib/fontisan/models/ucd.rb
460
- - lib/fontisan/models/ucd/ucd.rb
461
- - lib/fontisan/models/ucd/ucd_char.rb
462
409
  - lib/fontisan/models/unicode_mappings.rb
463
410
  - lib/fontisan/models/validation_report.rb
464
411
  - lib/fontisan/models/variable_font_info.rb
@@ -597,18 +544,6 @@ files:
597
544
  - lib/fontisan/type1/ttf_to_type1_converter.rb
598
545
  - lib/fontisan/type1/upm_scaler.rb
599
546
  - lib/fontisan/type1_font.rb
600
- - lib/fontisan/ucd.rb
601
- - lib/fontisan/ucd/aggregator.rb
602
- - lib/fontisan/ucd/cache_manager.rb
603
- - lib/fontisan/ucd/config.rb
604
- - lib/fontisan/ucd/download_error.rb
605
- - lib/fontisan/ucd/downloader.rb
606
- - lib/fontisan/ucd/error.rb
607
- - lib/fontisan/ucd/index.rb
608
- - lib/fontisan/ucd/index_builder.rb
609
- - lib/fontisan/ucd/range_entry.rb
610
- - lib/fontisan/ucd/unknown_version_error.rb
611
- - lib/fontisan/ucd/version_resolver.rb
612
547
  - lib/fontisan/utilities.rb
613
548
  - lib/fontisan/utilities/brotli_wrapper.rb
614
549
  - lib/fontisan/utilities/checksum_calculator.rb
@@ -675,6 +610,7 @@ metadata:
675
610
  source_code_uri: https://github.com/fontist/fontisan
676
611
  changelog_uri: https://github.com/fontist/fontisan/blob/main/CHANGELOG.md
677
612
  rubygems_mfa_required: 'true'
613
+ post_install_message:
678
614
  rdoc_options: []
679
615
  require_paths:
680
616
  - lib
@@ -689,7 +625,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
689
625
  - !ruby/object:Gem::Version
690
626
  version: '0'
691
627
  requirements: []
692
- rubygems_version: 3.6.9
628
+ rubygems_version: 3.5.22
629
+ signing_key:
693
630
  specification_version: 4
694
631
  summary: Font analysis tools and utilities for OpenType fonts
695
632
  test_files: []
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fontisan
4
- module Audit
5
- # Coalesces a flat codepoint list into contiguous {Models::Audit::CodepointRange}s.
6
- #
7
- # Single static call site, deterministic output. Used by the Coverage
8
- # extractor to produce the compact range view that is the default
9
- # AuditReport shape.
10
- module CodepointRangeCoalescer
11
- module_function
12
-
13
- # @param codepoints [Enumerable<Integer>] any enumeration of integers
14
- # @return [Array<Models::Audit::CodepointRange>] contiguous, sorted
15
- def call(codepoints)
16
- return [] if codepoints.nil? || codepoints.empty?
17
-
18
- sorted = codepoints.sort.uniq
19
- ranges = []
20
- range_start = sorted[0]
21
- prev = sorted[0]
22
-
23
- sorted[1..].each do |cp|
24
- next if cp == prev # defensive: .uniq already handles this
25
-
26
- if cp == prev + 1
27
- prev = cp
28
- else
29
- ranges << Models::Audit::CodepointRange.new(first_cp: range_start,
30
- last_cp: prev)
31
- range_start = cp
32
- prev = cp
33
- end
34
- end
35
- ranges << Models::Audit::CodepointRange.new(first_cp: range_start,
36
- last_cp: prev)
37
- ranges
38
- end
39
- end
40
- end
41
- end
@@ -1,122 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Fontisan
4
- module Audit
5
- # Value object carrying everything an extractor needs to do its job.
6
- #
7
- # Extractors never reach back into AuditCommand state — they read
8
- # exclusively from the Context. Shared derived data (codepoints,
9
- # UCD indices, source format) is memoized here so multiple
10
- # extractors don't recompute it.
11
- class Context
12
- attr_reader :font, :font_path, :font_index, :num_fonts_in_source,
13
- :options
14
-
15
- def initialize(font:, font_path:, font_index:, num_fonts_in_source:,
16
- options:)
17
- @font = font
18
- @font_path = font_path
19
- @font_index = font_index
20
- @num_fonts_in_source = num_fonts_in_source
21
- @options = options
22
- end
23
-
24
- def codepoints
25
- @codepoints ||= extract_codepoints
26
- end
27
-
28
- def ucd
29
- @ucd ||= resolve_ucd
30
- end
31
-
32
- def cldr
33
- return nil unless @options[:with_language_coverage]
34
-
35
- @cldr ||= resolve_cldr
36
- end
37
-
38
- def source_format
39
- @source_format ||= FontLoader.detect_format(@font_path)&.to_s
40
- end
41
-
42
- def all_codepoints?
43
- @options[:all_codepoints] == true
44
- end
45
-
46
- private
47
-
48
- def extract_codepoints
49
- return [] unless @font.has_table?(Constants::CMAP_TAG)
50
-
51
- @font.table(Constants::CMAP_TAG).unicode_mappings.keys
52
- end
53
-
54
- def resolve_ucd
55
- version = Ucd::VersionResolver.resolve(@options[:ucd_version])
56
-
57
- with_local_indices(version) do |blocks_path, scripts_path|
58
- {
59
- version: version,
60
- blocks_index: Ucd::Index.load(blocks_path),
61
- scripts_index: Ucd::Index.load(scripts_path),
62
- warning: nil,
63
- }
64
- end
65
- rescue Ucd::UnknownVersionError => e
66
- { version: nil, blocks_index: nil, scripts_index: nil,
67
- warning: "UCD version rejected: #{e.message}" }
68
- rescue StandardError => e
69
- version_ref = @ucd&.fetch(:version, nil)
70
- {
71
- version: version_ref,
72
- blocks_index: nil,
73
- scripts_index: nil,
74
- warning: "UCD unavailable for version #{version_ref}: #{e.message}",
75
- }
76
- end
77
-
78
- def with_local_indices(version)
79
- unless Ucd::CacheManager.cached?(version)
80
- Ucd::Downloader.download(version)
81
- end
82
- unless Ucd::CacheManager.blocks_index_path(version).exist?
83
- Ucd::IndexBuilder.build(version)
84
- end
85
- yield Ucd::CacheManager.blocks_index_path(version),
86
- Ucd::CacheManager.scripts_index_path(version)
87
- end
88
-
89
- def resolve_cldr
90
- version = Cldr::VersionResolver.resolve(@options[:cldr_version])
91
-
92
- with_local_languages_index(version) do |index_path|
93
- {
94
- version: version,
95
- index: Cldr::Index.load(index_path),
96
- warning: nil,
97
- }
98
- end
99
- rescue Cldr::UnknownVersionError => e
100
- { version: nil, index: nil,
101
- warning: "CLDR version rejected: #{e.message}" }
102
- rescue StandardError => e
103
- version_ref = @cldr&.fetch(:version, nil)
104
- {
105
- version: version_ref,
106
- index: nil,
107
- warning: "CLDR unavailable for version #{version_ref}: #{e.message}",
108
- }
109
- end
110
-
111
- def with_local_languages_index(version)
112
- unless Cldr::CacheManager.cached?(version)
113
- Cldr::Downloader.download(version)
114
- end
115
- unless Cldr::CacheManager.languages_index_path(version).exist?
116
- Cldr::IndexBuilder.build(version)
117
- end
118
- yield Cldr::CacheManager.languages_index_path(version)
119
- end
120
- end
121
- end
122
- end