docyard 1.0.2 → 1.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 (91) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -1
  3. data/lib/docyard/build/asset_bundler.rb +7 -33
  4. data/lib/docyard/build/file_copier.rb +7 -15
  5. data/lib/docyard/build/llms_txt_generator.rb +0 -2
  6. data/lib/docyard/build/sitemap_generator.rb +1 -1
  7. data/lib/docyard/build/static_generator.rb +30 -32
  8. data/lib/docyard/build/step_runner.rb +88 -0
  9. data/lib/docyard/build/validator.rb +98 -0
  10. data/lib/docyard/builder.rb +82 -55
  11. data/lib/docyard/cli.rb +36 -4
  12. data/lib/docyard/components/aliases.rb +0 -4
  13. data/lib/docyard/components/processors/callout_processor.rb +1 -1
  14. data/lib/docyard/components/processors/code_block_diff_preprocessor.rb +1 -1
  15. data/lib/docyard/components/processors/code_block_focus_preprocessor.rb +1 -1
  16. data/lib/docyard/components/processors/code_block_options_preprocessor.rb +2 -2
  17. data/lib/docyard/components/processors/code_group_processor.rb +1 -1
  18. data/lib/docyard/components/processors/icon_processor.rb +2 -2
  19. data/lib/docyard/components/processors/tabs_processor.rb +1 -1
  20. data/lib/docyard/config/schema/definition.rb +29 -0
  21. data/lib/docyard/config/schema/sections.rb +63 -0
  22. data/lib/docyard/config/schema/simple_sections.rb +78 -0
  23. data/lib/docyard/config/schema.rb +28 -31
  24. data/lib/docyard/config/type_validators.rb +121 -0
  25. data/lib/docyard/config/validator.rb +136 -61
  26. data/lib/docyard/config.rb +1 -13
  27. data/lib/docyard/diagnostic.rb +89 -0
  28. data/lib/docyard/diagnostic_context.rb +48 -0
  29. data/lib/docyard/doctor/code_block_checker.rb +136 -0
  30. data/lib/docyard/doctor/component_checker.rb +49 -0
  31. data/lib/docyard/doctor/component_checkers/abbreviation_checker.rb +74 -0
  32. data/lib/docyard/doctor/component_checkers/badge_checker.rb +71 -0
  33. data/lib/docyard/doctor/component_checkers/base.rb +111 -0
  34. data/lib/docyard/doctor/component_checkers/callout_checker.rb +34 -0
  35. data/lib/docyard/doctor/component_checkers/cards_checker.rb +57 -0
  36. data/lib/docyard/doctor/component_checkers/code_group_checker.rb +47 -0
  37. data/lib/docyard/doctor/component_checkers/details_checker.rb +51 -0
  38. data/lib/docyard/doctor/component_checkers/icon_checker.rb +36 -0
  39. data/lib/docyard/doctor/component_checkers/image_attrs_checker.rb +46 -0
  40. data/lib/docyard/doctor/component_checkers/space_after_colons_checker.rb +45 -0
  41. data/lib/docyard/doctor/component_checkers/steps_checker.rb +35 -0
  42. data/lib/docyard/doctor/component_checkers/tabs_checker.rb +35 -0
  43. data/lib/docyard/doctor/component_checkers/tooltip_checker.rb +67 -0
  44. data/lib/docyard/doctor/component_checkers/unknown_type_checker.rb +34 -0
  45. data/lib/docyard/doctor/config_checker.rb +19 -0
  46. data/lib/docyard/doctor/config_fixer.rb +87 -0
  47. data/lib/docyard/doctor/content_checker.rb +164 -0
  48. data/lib/docyard/doctor/file_scanner.rb +113 -0
  49. data/lib/docyard/doctor/image_checker.rb +103 -0
  50. data/lib/docyard/doctor/link_checker.rb +91 -0
  51. data/lib/docyard/doctor/markdown_fixer.rb +62 -0
  52. data/lib/docyard/doctor/orphan_checker.rb +82 -0
  53. data/lib/docyard/doctor/reporter.rb +152 -0
  54. data/lib/docyard/doctor/sidebar_checker.rb +127 -0
  55. data/lib/docyard/doctor/sidebar_fixer.rb +47 -0
  56. data/lib/docyard/doctor.rb +178 -0
  57. data/lib/docyard/editor_launcher.rb +119 -0
  58. data/lib/docyard/errors.rb +0 -49
  59. data/lib/docyard/initializer.rb +32 -39
  60. data/lib/docyard/navigation/sidebar/local_config_loader.rb +44 -21
  61. data/lib/docyard/rendering/icon_helpers.rb +1 -3
  62. data/lib/docyard/search/build_indexer.rb +39 -24
  63. data/lib/docyard/search/dev_indexer.rb +9 -23
  64. data/lib/docyard/server/dev_server.rb +55 -13
  65. data/lib/docyard/server/error_overlay.rb +73 -0
  66. data/lib/docyard/server/file_watcher.rb +0 -1
  67. data/lib/docyard/server/page_diagnostics.rb +27 -0
  68. data/lib/docyard/server/preview_server.rb +17 -13
  69. data/lib/docyard/server/rack_application.rb +64 -3
  70. data/lib/docyard/server/resolution_result.rb +0 -4
  71. data/lib/docyard/templates/assets/css/error-overlay.css +669 -0
  72. data/lib/docyard/templates/assets/css/variables.css +1 -1
  73. data/lib/docyard/templates/assets/fonts/Inter-Variable.woff2 +0 -0
  74. data/lib/docyard/templates/assets/js/components/relative-time.js +42 -0
  75. data/lib/docyard/templates/assets/js/error-overlay.js +547 -0
  76. data/lib/docyard/templates/assets/js/hot-reload.js +35 -7
  77. data/lib/docyard/templates/errors/404.html.erb +1 -1
  78. data/lib/docyard/templates/errors/500.html.erb +1 -1
  79. data/lib/docyard/templates/partials/_head.html.erb +1 -1
  80. data/lib/docyard/templates/partials/_page_actions.html.erb +1 -1
  81. data/lib/docyard/ui.rb +80 -0
  82. data/lib/docyard/utils/logging.rb +5 -1
  83. data/lib/docyard/utils/text_formatter.rb +0 -6
  84. data/lib/docyard/version.rb +1 -1
  85. data/lib/docyard.rb +4 -0
  86. metadata +47 -25
  87. data/lib/docyard/config/key_validator.rb +0 -30
  88. data/lib/docyard/config/validation_helpers.rb +0 -83
  89. data/lib/docyard/config/validators/navigation.rb +0 -43
  90. data/lib/docyard/config/validators/section.rb +0 -114
  91. data/lib/docyard/templates/assets/fonts/Inter-Variable.ttf +0 -0
data/lib/docyard/ui.rb ADDED
@@ -0,0 +1,80 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Docyard
4
+ module UI
5
+ CODES = {
6
+ red: 31,
7
+ green: 32,
8
+ yellow: 33,
9
+ cyan: 36,
10
+ bold: 1,
11
+ dim: 2
12
+ }.freeze
13
+
14
+ class << self
15
+ attr_writer :enabled
16
+
17
+ def enabled?
18
+ return @enabled unless @enabled.nil?
19
+
20
+ @enabled = determine_color_support
21
+ end
22
+
23
+ def reset!
24
+ @enabled = nil
25
+ end
26
+
27
+ def red(text)
28
+ wrap(text, CODES[:red])
29
+ end
30
+
31
+ def green(text)
32
+ wrap(text, CODES[:green])
33
+ end
34
+
35
+ def yellow(text)
36
+ wrap(text, CODES[:yellow])
37
+ end
38
+
39
+ def cyan(text)
40
+ wrap(text, CODES[:cyan])
41
+ end
42
+
43
+ def bold(text)
44
+ wrap(text, CODES[:bold])
45
+ end
46
+
47
+ def dim(text)
48
+ wrap(text, CODES[:dim])
49
+ end
50
+
51
+ def success(text)
52
+ wrap(text, CODES[:green], CODES[:bold])
53
+ end
54
+
55
+ def error(text)
56
+ wrap(text, CODES[:red], CODES[:bold])
57
+ end
58
+
59
+ def warning(text)
60
+ wrap(text, CODES[:yellow])
61
+ end
62
+
63
+ private
64
+
65
+ def wrap(text, *codes)
66
+ return text.to_s unless enabled?
67
+
68
+ prefix = codes.map { |c| "\e[#{c}m" }.join
69
+ "#{prefix}#{text}\e[0m"
70
+ end
71
+
72
+ def determine_color_support # rubocop:disable Naming/PredicateMethod
73
+ return false if ENV.key?("NO_COLOR")
74
+ return false unless $stdout.tty?
75
+
76
+ true
77
+ end
78
+ end
79
+ end
80
+ end
@@ -64,9 +64,13 @@ module Docyard
64
64
  def format_message(severity, msg)
65
65
  case severity
66
66
  when "DEBUG"
67
- "[DEBUG] #{msg}\n"
67
+ "#{UI.dim('[DEBUG]')} #{msg}\n"
68
68
  when "INFO"
69
69
  "#{msg}\n"
70
+ when "WARN"
71
+ "#{UI.warning('[WARN]')} #{msg}\n"
72
+ when "ERROR"
73
+ "#{UI.error('[ERROR]')} #{msg}\n"
70
74
  else
71
75
  "[#{severity}] #{msg}\n"
72
76
  end
@@ -11,12 +11,6 @@ module Docyard
11
11
  .map(&:capitalize)
12
12
  .join(" ")
13
13
  end
14
-
15
- def self.slugify(string)
16
- string.downcase
17
- .gsub(/\s+/, "-")
18
- .gsub(/[^a-z0-9-]/, "")
19
- end
20
14
  end
21
15
  end
22
16
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Docyard
4
- VERSION = "1.0.2"
4
+ VERSION = "1.1.0"
5
5
  end
data/lib/docyard.rb CHANGED
@@ -3,6 +3,8 @@
3
3
  require_relative "docyard/version"
4
4
  require_relative "docyard/constants"
5
5
  require_relative "docyard/errors"
6
+ require_relative "docyard/diagnostic"
7
+ require_relative "docyard/ui"
6
8
  require_relative "docyard/utils/logging"
7
9
 
8
10
  require_relative "docyard/utils/text_formatter"
@@ -37,5 +39,7 @@ require_relative "docyard/build/asset_bundler"
37
39
  require_relative "docyard/build/file_copier"
38
40
  require_relative "docyard/build/sitemap_generator"
39
41
 
42
+ require_relative "docyard/doctor"
43
+
40
44
  module Docyard
41
45
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: docyard
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.2
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sanif Himani
8
- autorequire:
9
8
  bindir: exe
10
9
  cert_chain: []
11
- date: 2026-01-23 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: cssminify
@@ -164,20 +163,6 @@ dependencies:
164
163
  - - "~>"
165
164
  - !ruby/object:Gem::Version
166
165
  version: '1.4'
167
- - !ruby/object:Gem::Dependency
168
- name: tty-progressbar
169
- requirement: !ruby/object:Gem::Requirement
170
- requirements:
171
- - - "~>"
172
- - !ruby/object:Gem::Version
173
- version: '0.18'
174
- type: :runtime
175
- prerelease: false
176
- version_requirements: !ruby/object:Gem::Requirement
177
- requirements:
178
- - - "~>"
179
- - !ruby/object:Gem::Version
180
- version: '0.18'
181
166
  description: Generate beautiful documentation sites from Markdown
182
167
  email:
183
168
  - sanifhimani92@gmail.com
@@ -199,6 +184,8 @@ files:
199
184
  - lib/docyard/build/root_fallback_generator.rb
200
185
  - lib/docyard/build/sitemap_generator.rb
201
186
  - lib/docyard/build/static_generator.rb
187
+ - lib/docyard/build/step_runner.rb
188
+ - lib/docyard/build/validator.rb
202
189
  - lib/docyard/builder.rb
203
190
  - lib/docyard/cli.rb
204
191
  - lib/docyard/components/aliases.rb
@@ -244,15 +231,46 @@ files:
244
231
  - lib/docyard/config.rb
245
232
  - lib/docyard/config/analytics_resolver.rb
246
233
  - lib/docyard/config/branding_resolver.rb
247
- - lib/docyard/config/key_validator.rb
248
234
  - lib/docyard/config/logo_detector.rb
249
235
  - lib/docyard/config/schema.rb
236
+ - lib/docyard/config/schema/definition.rb
237
+ - lib/docyard/config/schema/sections.rb
238
+ - lib/docyard/config/schema/simple_sections.rb
250
239
  - lib/docyard/config/section.rb
251
- - lib/docyard/config/validation_helpers.rb
240
+ - lib/docyard/config/type_validators.rb
252
241
  - lib/docyard/config/validator.rb
253
- - lib/docyard/config/validators/navigation.rb
254
- - lib/docyard/config/validators/section.rb
255
242
  - lib/docyard/constants.rb
243
+ - lib/docyard/diagnostic.rb
244
+ - lib/docyard/diagnostic_context.rb
245
+ - lib/docyard/doctor.rb
246
+ - lib/docyard/doctor/code_block_checker.rb
247
+ - lib/docyard/doctor/component_checker.rb
248
+ - lib/docyard/doctor/component_checkers/abbreviation_checker.rb
249
+ - lib/docyard/doctor/component_checkers/badge_checker.rb
250
+ - lib/docyard/doctor/component_checkers/base.rb
251
+ - lib/docyard/doctor/component_checkers/callout_checker.rb
252
+ - lib/docyard/doctor/component_checkers/cards_checker.rb
253
+ - lib/docyard/doctor/component_checkers/code_group_checker.rb
254
+ - lib/docyard/doctor/component_checkers/details_checker.rb
255
+ - lib/docyard/doctor/component_checkers/icon_checker.rb
256
+ - lib/docyard/doctor/component_checkers/image_attrs_checker.rb
257
+ - lib/docyard/doctor/component_checkers/space_after_colons_checker.rb
258
+ - lib/docyard/doctor/component_checkers/steps_checker.rb
259
+ - lib/docyard/doctor/component_checkers/tabs_checker.rb
260
+ - lib/docyard/doctor/component_checkers/tooltip_checker.rb
261
+ - lib/docyard/doctor/component_checkers/unknown_type_checker.rb
262
+ - lib/docyard/doctor/config_checker.rb
263
+ - lib/docyard/doctor/config_fixer.rb
264
+ - lib/docyard/doctor/content_checker.rb
265
+ - lib/docyard/doctor/file_scanner.rb
266
+ - lib/docyard/doctor/image_checker.rb
267
+ - lib/docyard/doctor/link_checker.rb
268
+ - lib/docyard/doctor/markdown_fixer.rb
269
+ - lib/docyard/doctor/orphan_checker.rb
270
+ - lib/docyard/doctor/reporter.rb
271
+ - lib/docyard/doctor/sidebar_checker.rb
272
+ - lib/docyard/doctor/sidebar_fixer.rb
273
+ - lib/docyard/editor_launcher.rb
256
274
  - lib/docyard/errors.rb
257
275
  - lib/docyard/initializer.rb
258
276
  - lib/docyard/navigation/breadcrumb_builder.rb
@@ -281,7 +299,9 @@ files:
281
299
  - lib/docyard/search/pagefind_support.rb
282
300
  - lib/docyard/server/asset_handler.rb
283
301
  - lib/docyard/server/dev_server.rb
302
+ - lib/docyard/server/error_overlay.rb
284
303
  - lib/docyard/server/file_watcher.rb
304
+ - lib/docyard/server/page_diagnostics.rb
285
305
  - lib/docyard/server/pagefind_handler.rb
286
306
  - lib/docyard/server/preview_server.rb
287
307
  - lib/docyard/server/rack_application.rb
@@ -318,6 +338,7 @@ files:
318
338
  - lib/docyard/templates/assets/css/components/theme-toggle.css
319
339
  - lib/docyard/templates/assets/css/components/tooltip.css
320
340
  - lib/docyard/templates/assets/css/components/video.css
341
+ - lib/docyard/templates/assets/css/error-overlay.css
321
342
  - lib/docyard/templates/assets/css/landing.css
322
343
  - lib/docyard/templates/assets/css/layout.css
323
344
  - lib/docyard/templates/assets/css/main.css
@@ -326,7 +347,7 @@ files:
326
347
  - lib/docyard/templates/assets/css/typography.css
327
348
  - lib/docyard/templates/assets/css/variables.css
328
349
  - lib/docyard/templates/assets/favicon.svg
329
- - lib/docyard/templates/assets/fonts/Inter-Variable.ttf
350
+ - lib/docyard/templates/assets/fonts/Inter-Variable.woff2
330
351
  - lib/docyard/templates/assets/js/components/abbreviation.js
331
352
  - lib/docyard/templates/assets/js/components/banner.js
332
353
  - lib/docyard/templates/assets/js/components/code-block.js
@@ -337,12 +358,14 @@ files:
337
358
  - lib/docyard/templates/assets/js/components/heading-anchor.js
338
359
  - lib/docyard/templates/assets/js/components/lightbox.js
339
360
  - lib/docyard/templates/assets/js/components/navigation.js
361
+ - lib/docyard/templates/assets/js/components/relative-time.js
340
362
  - lib/docyard/templates/assets/js/components/search.js
341
363
  - lib/docyard/templates/assets/js/components/sidebar-toggle.js
342
364
  - lib/docyard/templates/assets/js/components/tab-navigation.js
343
365
  - lib/docyard/templates/assets/js/components/table-of-contents.js
344
366
  - lib/docyard/templates/assets/js/components/tabs.js
345
367
  - lib/docyard/templates/assets/js/components/tooltip.js
368
+ - lib/docyard/templates/assets/js/error-overlay.js
346
369
  - lib/docyard/templates/assets/js/hot-reload.js
347
370
  - lib/docyard/templates/assets/js/theme.js
348
371
  - lib/docyard/templates/assets/logo-dark.svg
@@ -394,6 +417,7 @@ files:
394
417
  - lib/docyard/templates/partials/_table_of_contents_toggle.html.erb
395
418
  - lib/docyard/templates/partials/_tabs.html.erb
396
419
  - lib/docyard/templates/partials/_theme_toggle.html.erb
420
+ - lib/docyard/ui.rb
397
421
  - lib/docyard/utils/git_info.rb
398
422
  - lib/docyard/utils/hash_utils.rb
399
423
  - lib/docyard/utils/html_helpers.rb
@@ -414,7 +438,6 @@ metadata:
414
438
  documentation_uri: https://docyard.dev
415
439
  bug_tracker_uri: https://github.com/sanifhimani/docyard/issues
416
440
  rubygems_mfa_required: 'true'
417
- post_install_message:
418
441
  rdoc_options: []
419
442
  require_paths:
420
443
  - lib
@@ -429,8 +452,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
429
452
  - !ruby/object:Gem::Version
430
453
  version: '0'
431
454
  requirements: []
432
- rubygems_version: 3.5.22
433
- signing_key:
455
+ rubygems_version: 3.7.2
434
456
  specification_version: 4
435
457
  summary: Generate beautiful documentation sites from Markdown
436
458
  test_files: []
@@ -1,30 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Docyard
4
- class Config
5
- module KeyValidator
6
- class << self
7
- def validate(hash, valid_keys, context:)
8
- return [] unless hash.is_a?(Hash)
9
-
10
- unknown = hash.keys.map(&:to_s) - valid_keys
11
- unknown.map { |key| build_error(key, valid_keys, context) }
12
- end
13
-
14
- private
15
-
16
- def build_error(key, valid_keys, context)
17
- suggestion = find_suggestion(key, valid_keys)
18
- msg = "unknown key '#{key}'"
19
- msg += ". Did you mean '#{suggestion}'?" if suggestion
20
- { context: context, message: msg }
21
- end
22
-
23
- def find_suggestion(key, valid_keys)
24
- checker = DidYouMean::SpellChecker.new(dictionary: valid_keys)
25
- checker.correct(key).first
26
- end
27
- end
28
- end
29
- end
30
- end
@@ -1,83 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Docyard
4
- class Config
5
- module ValidationHelpers
6
- private
7
-
8
- def validate_string(value, field_name)
9
- return if value.nil? || value.is_a?(String)
10
-
11
- add_error(field: field_name, error: "must be a string", got: value.class.name, fix: "Change to a string value")
12
- end
13
-
14
- def validate_boolean(value, field_name)
15
- return if [true, false].include?(value)
16
-
17
- add_error(field: field_name, error: "must be true or false", got: value.inspect, fix: "Change to true or false")
18
- end
19
-
20
- def validate_url(value, field_name)
21
- return if value.nil? || value.is_a?(String)
22
-
23
- add_error(field: field_name, error: "must be a URL string", got: value.class.name,
24
- fix: "Change to a URL string")
25
- end
26
-
27
- def validate_array(value, field_name)
28
- return if value.nil? || value.is_a?(Array)
29
-
30
- add_array_error(field_name)
31
- end
32
-
33
- def validate_file_path_or_url(value, field_name)
34
- return if value.nil?
35
- return add_type_error(field_name, "file path or URL (string)", value.class.name) unless value.is_a?(String)
36
- return if url?(value)
37
-
38
- public_dir = File.join(@config["source"] || "docs", "public")
39
- file_path = File.absolute_path?(value) ? value : File.join(public_dir, value)
40
- return if File.exist?(file_path)
41
-
42
- add_error(field: field_name, error: "file not found", got: value,
43
- fix: "Place the file in #{public_dir}/ directory (e.g., 'logo.svg' for #{public_dir}/logo.svg)")
44
- end
45
-
46
- def validate_no_slashes(value, field_name)
47
- return if value.nil? || !value.is_a?(String)
48
- return unless value.include?("/") || value.include?("\\")
49
-
50
- add_error(field: field_name, error: "cannot contain slashes", got: value,
51
- fix: "Use a simple directory name like 'dist' or '_site'")
52
- end
53
-
54
- def validate_starts_with_slash(value, field_name)
55
- return if value.nil? || value.start_with?("/")
56
-
57
- add_error(field: field_name, error: "must start with /", got: value, fix: "Change to '/#{value}'")
58
- end
59
-
60
- def url?(value)
61
- value.match?(%r{\Ahttps?://})
62
- end
63
-
64
- def add_error(error_data)
65
- @errors << error_data
66
- end
67
-
68
- def add_type_error(field, expected, got)
69
- add_error(field: field, error: "must be a #{expected}", got: got, fix: "Change to a #{expected}")
70
- end
71
-
72
- def add_hash_error(field)
73
- add_error(field: field, error: "must be a hash", got: @config[field].class.name,
74
- fix: "Change to a hash with platform names as keys and URLs as values")
75
- end
76
-
77
- def add_array_error(field)
78
- value = field.split(".").reduce(@config) { |h, k| h&.[](k) }
79
- add_error(field: field, error: "must be an array", got: value.class.name, fix: "Change to an array")
80
- end
81
- end
82
- end
83
- end
@@ -1,43 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Docyard
4
- class Config
5
- module Validators
6
- module Navigation
7
- private
8
-
9
- def validate_navigation_section
10
- cta = @config.dig("navigation", "cta")
11
- return if cta.nil?
12
- return add_array_error("navigation.cta") unless cta.is_a?(Array)
13
-
14
- validate_cta_max_count(cta)
15
- validate_cta_items(cta)
16
- end
17
-
18
- def validate_cta_items(cta)
19
- cta.each_with_index do |item, idx|
20
- validate_string(item["text"], "navigation.cta[#{idx}].text")
21
- validate_string(item["href"], "navigation.cta[#{idx}].href")
22
- validate_cta_variant(item["variant"], idx) if item.key?("variant")
23
- validate_boolean(item["external"], "navigation.cta[#{idx}].external") if item.key?("external")
24
- end
25
- end
26
-
27
- def validate_cta_max_count(cta)
28
- return if cta.length <= 2
29
-
30
- add_error(field: "navigation.cta", error: "maximum 2 CTAs allowed",
31
- got: "#{cta.length} items", fix: "Remove extra CTA items to have at most 2")
32
- end
33
-
34
- def validate_cta_variant(variant, idx)
35
- return if variant.nil? || %w[primary secondary].include?(variant)
36
-
37
- add_error(field: "navigation.cta[#{idx}].variant", error: "must be 'primary' or 'secondary'",
38
- got: variant, fix: "Change to 'primary' or 'secondary'")
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,114 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Docyard
4
- class Config
5
- module Validators
6
- module Section
7
- private
8
-
9
- def validate_top_level
10
- validate_string(@config["title"], "title")
11
- validate_string(@config["description"], "description")
12
- end
13
-
14
- def validate_branding_section
15
- branding = @config["branding"]
16
- return unless branding
17
-
18
- validate_file_path_or_url(branding["logo"], "branding.logo")
19
- validate_file_path_or_url(branding["favicon"], "branding.favicon")
20
- validate_boolean(branding["credits"], "branding.credits") if branding.key?("credits")
21
- end
22
-
23
- def validate_socials_section
24
- socials = @config["socials"]
25
- return unless socials
26
- return add_hash_error("socials") unless socials.is_a?(Hash)
27
-
28
- socials.each { |platform, url| validate_url(url, "socials.#{platform}") unless platform == "custom" }
29
- validate_custom_socials(socials["custom"]) if socials.key?("custom")
30
- end
31
-
32
- def validate_custom_socials(custom)
33
- return if custom.nil?
34
- return add_array_error("socials.custom") unless custom.is_a?(Array)
35
-
36
- custom.each_with_index do |item, index|
37
- validate_string(item["icon"], "socials.custom[#{index}].icon")
38
- validate_url(item["href"], "socials.custom[#{index}].href")
39
- end
40
- end
41
-
42
- def validate_tabs_section
43
- tabs = @config["tabs"]
44
- return unless tabs
45
- return add_array_error("tabs") unless tabs.is_a?(Array)
46
-
47
- tabs.each_with_index do |tab, index|
48
- validate_string(tab["text"], "tabs[#{index}].text")
49
- validate_string(tab["href"], "tabs[#{index}].href")
50
- validate_boolean(tab["external"], "tabs[#{index}].external") if tab.key?("external")
51
- end
52
- end
53
-
54
- def validate_sidebar_setting
55
- sidebar = @config["sidebar"]
56
- return if sidebar.nil? || Config::SIDEBAR_MODES.include?(sidebar)
57
-
58
- add_error(
59
- field: "sidebar",
60
- error: "must be one of: #{Config::SIDEBAR_MODES.join(', ')}",
61
- got: sidebar.inspect,
62
- fix: "Change to 'config', 'auto', or 'distributed'"
63
- )
64
- end
65
-
66
- def validate_build_section
67
- build = @config["build"]
68
- return unless build
69
-
70
- validate_string(build["output"], "build.output")
71
- validate_no_slashes(build["output"], "build.output")
72
- validate_string(build["base"], "build.base")
73
- validate_starts_with_slash(build["base"], "build.base")
74
- end
75
-
76
- def validate_search_section
77
- search = @config["search"]
78
- return unless search
79
-
80
- validate_boolean(search["enabled"], "search.enabled") if search.key?("enabled")
81
- validate_string(search["placeholder"], "search.placeholder") if search.key?("placeholder")
82
- validate_array(search["exclude"], "search.exclude") if search.key?("exclude")
83
- end
84
-
85
- def validate_announcement_section
86
- announcement = @config["announcement"]
87
- return unless announcement.is_a?(Hash)
88
-
89
- validate_string(announcement["text"], "announcement.text") if announcement.key?("text")
90
- end
91
-
92
- def validate_feedback_section
93
- feedback = @config["feedback"]
94
- return unless feedback.is_a?(Hash) && feedback["enabled"] == true
95
- return if analytics_configured?
96
-
97
- add_error(
98
- field: "feedback.enabled",
99
- error: "requires analytics to be configured",
100
- got: "feedback enabled without analytics",
101
- fix: "Configure analytics (google, plausible, fathom, or script) to collect feedback responses"
102
- )
103
- end
104
-
105
- def analytics_configured?
106
- analytics = @config["analytics"]
107
- return false unless analytics.is_a?(Hash)
108
-
109
- analytics["google"] || analytics["plausible"] || analytics["fathom"] || analytics["script"]
110
- end
111
- end
112
- end
113
- end
114
- end