fontist 3.0.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/discover-fonts.yml +76 -0
  3. data/.github/workflows/rake.yml +103 -8
  4. data/.rubocop_todo.yml +179 -139
  5. data/TODO.audit-docs.md +164 -0
  6. data/TODO.improve-docs.md +114 -0
  7. data/TODO.upgrade-excavate.md +107 -0
  8. data/docs/guide/formulas.md +37 -1
  9. data/docs/guide/how-it-works.md +13 -0
  10. data/docs/guide/platforms/windows.md +67 -0
  11. data/fontist.gemspec +2 -2
  12. data/lib/fontist/cache/store.rb +1 -1
  13. data/lib/fontist/cli.rb +2 -1
  14. data/lib/fontist/errors.rb +24 -3
  15. data/lib/fontist/extract.rb +1 -0
  16. data/lib/fontist/font.rb +2 -2
  17. data/lib/fontist/font_finder.rb +1 -2
  18. data/lib/fontist/font_installer.rb +16 -14
  19. data/lib/fontist/format_matcher.rb +4 -2
  20. data/lib/fontist/format_spec.rb +1 -1
  21. data/lib/fontist/formula.rb +15 -3
  22. data/lib/fontist/formula_picker.rb +5 -3
  23. data/lib/fontist/import/create_formula.rb +5 -0
  24. data/lib/fontist/import/formula_builder.rb +10 -1
  25. data/lib/fontist/import/google/data_sources/github.rb +4 -4
  26. data/lib/fontist/import/google/font_database.rb +8 -8
  27. data/lib/fontist/import/google/formula_builders/formula_builder_v4.rb +1 -1
  28. data/lib/fontist/import/google/formula_builders/formula_builder_v5.rb +9 -3
  29. data/lib/fontist/import/google/metadata_adapter.rb +6 -6
  30. data/lib/fontist/import/google/models/font_family.rb +1 -1
  31. data/lib/fontist/import/import_display.rb +5 -5
  32. data/lib/fontist/import/macos_importer.rb +1 -1
  33. data/lib/fontist/import/upgrade_formulas.rb +1 -3
  34. data/lib/fontist/import/v4_to_v5_migrator.rb +2 -1
  35. data/lib/fontist/import/windows/fod_capabilities.yml +654 -0
  36. data/lib/fontist/import/windows/windows_license.txt +4 -0
  37. data/lib/fontist/import/windows.rb +162 -0
  38. data/lib/fontist/import.rb +3 -1
  39. data/lib/fontist/import_source.rb +1 -0
  40. data/lib/fontist/indexes/directory_snapshot.rb +2 -2
  41. data/lib/fontist/indexes/incremental_scanner.rb +2 -2
  42. data/lib/fontist/indexes.rb +8 -4
  43. data/lib/fontist/macos/catalog/asset.rb +2 -2
  44. data/lib/fontist/macos_import_source.rb +0 -1
  45. data/lib/fontist/repo.rb +1 -1
  46. data/lib/fontist/resource.rb +5 -1
  47. data/lib/fontist/resources/windows_fod_resource.rb +51 -0
  48. data/lib/fontist/resources.rb +1 -0
  49. data/lib/fontist/system_index.rb +5 -5
  50. data/lib/fontist/utils/downloader.rb +8 -3
  51. data/lib/fontist/utils/system.rb +19 -2
  52. data/lib/fontist/validation.rb +1 -1
  53. data/lib/fontist/validator.rb +2 -2
  54. data/lib/fontist/version.rb +1 -1
  55. data/lib/fontist/windows_fod_metadata.rb +83 -0
  56. data/lib/fontist/windows_import_source.rb +54 -0
  57. data/lib/fontist.rb +4 -1
  58. data/script/generate_windows_formulas.rb +24 -0
  59. data/script/validate_windows_fod_ci.rb +175 -0
  60. metadata +17 -6
@@ -0,0 +1,175 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # Validate Windows FOD capabilities against live Windows system
5
+ #
6
+ # Usage:
7
+ # bundle exec ruby script/validate_windows_fod_ci.rb
8
+ #
9
+ # This script:
10
+ # 1. Loads fod_capabilities.yml
11
+ # 2. Queries Windows for real FOD capabilities via PowerShell
12
+ # 3. Compares our YAML capability names against what Windows reports
13
+ # 4. For installed capabilities, checks that expected font files exist
14
+ # 5. Exits 0 on success, 1 on critical mismatches
15
+
16
+ require "yaml"
17
+ require "set"
18
+
19
+ FONTS_DIR = 'C:\Windows\Fonts'
20
+ YAML_PATH = File.expand_path(
21
+ "../lib/fontist/import/windows/fod_capabilities.yml",
22
+ __dir__,
23
+ )
24
+
25
+ def main
26
+ unless Gem.win_platform?
27
+ puts "SKIP: Not running on Windows"
28
+ exit 0
29
+ end
30
+
31
+ puts "=== Windows FOD Capability Validation ==="
32
+ puts ""
33
+
34
+ yaml_caps = load_yaml_capabilities
35
+ live_caps = query_live_capabilities
36
+
37
+ puts "YAML capabilities: #{yaml_caps.size}"
38
+ puts "Live capabilities: #{live_caps.size}"
39
+ puts ""
40
+
41
+ matched, missing_from_yaml, extra_in_yaml = compare(yaml_caps, live_caps)
42
+
43
+ print_results(matched, missing_from_yaml, extra_in_yaml)
44
+
45
+ errors = check_installed_fonts(yaml_caps, live_caps)
46
+
47
+ puts ""
48
+ summarize(matched, missing_from_yaml, extra_in_yaml, errors)
49
+ end
50
+
51
+ def load_yaml_capabilities
52
+ data = YAML.safe_load(File.read(YAML_PATH))
53
+ data.fetch("capabilities", {})
54
+ rescue StandardError => e
55
+ puts "ERROR: Failed to load YAML: #{e.message}"
56
+ exit 1
57
+ end
58
+
59
+ def query_live_capabilities
60
+ output = `powershell -NoProfile -Command "Get-WindowsCapability -Online -Name 'Language.Fonts.*' | Select-Object Name, State | ConvertTo-Csv -NoTypeInformation"`
61
+
62
+ unless $?.success?
63
+ puts "ERROR: PowerShell command failed (exit #{$?.exitstatus})"
64
+ exit 1
65
+ end
66
+
67
+ caps = {}
68
+ output.each_line do |line|
69
+ line = line.strip.delete('"')
70
+ next if line.empty? || line.start_with?("Name")
71
+
72
+ name, state = line.split(",", 2)
73
+ caps[name] = state if name && state
74
+ end
75
+ caps
76
+ end
77
+
78
+ def compare(yaml_caps, live_caps)
79
+ yaml_names = yaml_caps.keys.to_set
80
+ live_names = live_caps.keys.to_set
81
+
82
+ matched = yaml_names & live_names
83
+ missing_from_yaml = live_names - yaml_names
84
+ extra_in_yaml = yaml_names - live_names
85
+
86
+ [matched, missing_from_yaml, extra_in_yaml]
87
+ end
88
+
89
+ def print_results(matched, missing_from_yaml, extra_in_yaml)
90
+ puts "=== Matched (#{matched.size}) ==="
91
+ matched.sort.each { |name| puts " OK: #{name}" }
92
+
93
+ if missing_from_yaml.any?
94
+ puts ""
95
+ puts "=== Missing from our YAML (#{missing_from_yaml.size}) ==="
96
+ missing_from_yaml.sort.each { |name| puts " MISSING: #{name}" }
97
+ end
98
+
99
+ if extra_in_yaml.any?
100
+ puts ""
101
+ puts "=== Extra in our YAML (#{extra_in_yaml.size}) ==="
102
+ extra_in_yaml.sort.each { |name| puts " EXTRA: #{name}" }
103
+ end
104
+ end
105
+
106
+ def check_installed_fonts(yaml_caps, live_caps)
107
+ installed = live_caps.select { |_, state| state == "Installed" }
108
+ return [] if installed.empty?
109
+
110
+ puts ""
111
+ puts "=== Font File Checks for Installed Capabilities ==="
112
+
113
+ errors = []
114
+
115
+ installed.each_key do |cap_name|
116
+ cap_data = yaml_caps[cap_name]
117
+ next unless cap_data
118
+
119
+ fonts = cap_data.fetch("fonts", {})
120
+ fonts.each do |family_name, data|
121
+ files = data.fetch("files", [])
122
+ files.each do |filename|
123
+ path = File.join(FONTS_DIR, filename)
124
+ if File.exist?(path)
125
+ puts " OK: #{filename} (#{family_name})"
126
+ else
127
+ puts " MISSING: #{filename} (#{family_name}) — expected at #{path}"
128
+ errors << "#{cap_name}: #{filename} not found"
129
+ end
130
+ end
131
+ end
132
+ end
133
+
134
+ errors
135
+ end
136
+
137
+ def summarize(matched, missing_from_yaml, extra_in_yaml, font_errors)
138
+ puts "========================================="
139
+ puts " Validation Summary"
140
+ puts "========================================="
141
+ puts " Capability matches: #{matched.size}"
142
+ puts " Missing from our YAML: #{missing_from_yaml.size}"
143
+ puts " Extra in our YAML: #{extra_in_yaml.size}"
144
+ puts " Font file errors: #{font_errors.size}"
145
+ puts ""
146
+
147
+ if missing_from_yaml.any?
148
+ puts "WARNING: #{missing_from_yaml.size} capabilities exist on Windows but not in our YAML."
149
+ puts " Consider adding them to fod_capabilities.yml"
150
+ puts ""
151
+ end
152
+
153
+ if extra_in_yaml.any?
154
+ puts "WARNING: #{extra_in_yaml.size} capabilities in our YAML not found on this Windows version."
155
+ puts " These may be version-specific or renamed."
156
+ puts ""
157
+ end
158
+
159
+ if font_errors.any?
160
+ puts "WARNING: #{font_errors.size} font files missing for installed capabilities."
161
+ font_errors.each { |e| puts " - #{e}" }
162
+ puts ""
163
+ end
164
+
165
+ # Exit 1 only if we have zero matches (indicates a fundamental problem)
166
+ if matched.empty? && (missing_from_yaml.any? || extra_in_yaml.any?)
167
+ puts "CRITICAL: No capability names matched — our YAML may be completely wrong."
168
+ exit 1
169
+ end
170
+
171
+ puts "Validation passed."
172
+ exit 0
173
+ end
174
+
175
+ main
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fontist
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-04-14 00:00:00.000000000 Z
11
+ date: 2026-05-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: down
@@ -53,7 +53,7 @@ dependencies:
53
53
  version: '0.2'
54
54
  - - ">="
55
55
  - !ruby/object:Gem::Version
56
- version: 0.2.11
56
+ version: 0.2.16
57
57
  type: :runtime
58
58
  prerelease: false
59
59
  version_requirements: !ruby/object:Gem::Requirement
@@ -63,7 +63,7 @@ dependencies:
63
63
  version: '0.2'
64
64
  - - ">="
65
65
  - !ruby/object:Gem::Version
66
- version: 0.2.11
66
+ version: 0.2.16
67
67
  - !ruby/object:Gem::Dependency
68
68
  name: fuzzy_match
69
69
  requirement: !ruby/object:Gem::Requirement
@@ -112,14 +112,14 @@ dependencies:
112
112
  requirements:
113
113
  - - "~>"
114
114
  - !ruby/object:Gem::Version
115
- version: '0.7'
115
+ version: 0.8.0
116
116
  type: :runtime
117
117
  prerelease: false
118
118
  version_requirements: !ruby/object:Gem::Requirement
119
119
  requirements:
120
120
  - - "~>"
121
121
  - !ruby/object:Gem::Version
122
- version: '0.7'
122
+ version: 0.8.0
123
123
  - !ruby/object:Gem::Dependency
124
124
  name: marcel
125
125
  requirement: !ruby/object:Gem::Requirement
@@ -273,7 +273,10 @@ files:
273
273
  - LICENSE.txt
274
274
  - README.adoc
275
275
  - Rakefile
276
+ - TODO.audit-docs.md
276
277
  - TODO.fontist-v5.md
278
+ - TODO.improve-docs.md
279
+ - TODO.upgrade-excavate.md
277
280
  - docs/.gitignore
278
281
  - docs/.vitepress/config.ts
279
282
  - docs/.vitepress/data/cli-commands.json
@@ -434,6 +437,9 @@ files:
434
437
  - lib/fontist/import/text_helper.rb
435
438
  - lib/fontist/import/upgrade_formulas.rb
436
439
  - lib/fontist/import/v4_to_v5_migrator.rb
440
+ - lib/fontist/import/windows.rb
441
+ - lib/fontist/import/windows/fod_capabilities.yml
442
+ - lib/fontist/import/windows/windows_license.txt
437
443
  - lib/fontist/import_cli.rb
438
444
  - lib/fontist/import_source.rb
439
445
  - lib/fontist/index.rb
@@ -486,6 +492,7 @@ files:
486
492
  - lib/fontist/resources/apple_cdn_resource.rb
487
493
  - lib/fontist/resources/archive_resource.rb
488
494
  - lib/fontist/resources/google_resource.rb
495
+ - lib/fontist/resources/windows_fod_resource.rb
489
496
  - lib/fontist/sil_import_source.rb
490
497
  - lib/fontist/style_version.rb
491
498
  - lib/fontist/system.yml
@@ -506,9 +513,13 @@ files:
506
513
  - lib/fontist/validation.rb
507
514
  - lib/fontist/validator.rb
508
515
  - lib/fontist/version.rb
516
+ - lib/fontist/windows_fod_metadata.rb
517
+ - lib/fontist/windows_import_source.rb
509
518
  - lib/tasks/system_fonts.rake
510
519
  - script/capture_system_fonts
511
520
  - script/download_system_indexes
521
+ - script/generate_windows_formulas.rb
522
+ - script/validate_windows_fod_ci.rb
512
523
  homepage: https://github.com/fontist/fontist
513
524
  licenses:
514
525
  - BSD-2-Clause