Module: VivlioStarter::CLI::PreProcessCommands::LinkImageValidator
- Defined in:
- lib/vivlio_starter/cli/pre_process/link_image_validator.rb
Defined Under Namespace
Classes: ImageIssue, LinkIssue, ValidationReport
Class Method Summary collapse
-
.any_issues? ⇒ Boolean
蓄積されたレポートにエラー(issue)が1件以上あるか判定する.
-
.check_external_urls! ⇒ Object
蓄積された外部 URL に対して HTTP 到達性チェックを実行する.
-
.merge_into_report(filename, image_issues: [], link_issues: []) ⇒ Object
同じファイルのレポートへ issue を足し込む。 検証は段階ごとに分かれて走る(リンクは原稿、画像はパス解決後、コード インクルードはさらにあと)が、集計は 1 ファイル 1 レポートに保つ。.
-
.print_summary ⇒ Object
検証結果のサマリーを表示する.
-
.record_code_include_error(filename, line_number, code_name) ⇒ Object
コードインクルードエラーをレポートに記録する MarkdownTransformer から呼ばれ、preflight の終了コード判定に反映させる.
-
.reset! ⇒ Object
レポート蓄積をリセットする(ビルド開始時に呼ぶ).
-
.validate(content, filename, source_path: nil, config: resolve_config) ⇒ ValidationReport
リンクと画像をまとめて検証する(単発の検証向けの入口)。 ビルドの前処理は、それぞれを正しい段階で呼ぶために分けて使う。.
-
.validate_images(content, filename, source_path: nil, config: resolve_config) ⇒ Array<ImageIssue>
画像の存在を検証する。パス正規化とデータ展開のあとに適用すること。.
-
.validate_links(content, filename, config: resolve_config) ⇒ Array<LinkIssue>
原稿に書かれたリンクを検証する。前処理にかける前の原稿へ適用すること。.
Class Method Details
.any_issues? ⇒ Boolean
蓄積されたレポートにエラー(issue)が1件以上あるか判定する
217 218 219 220 221 |
# File 'lib/vivlio_starter/cli/pre_process/link_image_validator.rb', line 217 def any_issues? @monitor.synchronize do @reports.any? { |r| r.image_issues.any? || r.link_issues.any? } end end |
.check_external_urls! ⇒ Object
蓄積された外部 URL に対して HTTP 到達性チェックを実行する
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 |
# File 'lib/vivlio_starter/cli/pre_process/link_image_validator.rb', line 130 def check_external_urls! config = resolve_config return unless config[:verify_external_links] urls = @monitor.synchronize { @external_urls.dup } return if urls.empty? # URL を重複排除(同じ URL は 1 回だけチェック) unique_urls = urls.uniq { it[:url] } Common.log_action("[検証] 外部 URL の到達性を確認しています(#{unique_urls.size} 件)…") results = check_urls_batch(unique_urls, config) # 結果をレポートに反映 results.each do |result| next if result[:ok] issue = LinkIssue.new( filename: result[:filename], line_number: result[:line_number], url: result[:url], issue_type: :unreachable, status_code: result[:status_code], message: result[:message] ) add_link_issue_to_report(result[:filename], issue) record_to_registry(issue) end end |
.merge_into_report(filename, image_issues: [], link_issues: []) ⇒ Object
同じファイルのレポートへ issue を足し込む。 検証は段階ごとに分かれて走る(リンクは原稿、画像はパス解決後、コード インクルードはさらにあと)が、集計は 1 ファイル 1 レポートに保つ。
242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/vivlio_starter/cli/pre_process/link_image_validator.rb', line 242 def merge_into_report(filename, image_issues: [], link_issues: []) @monitor.synchronize do idx = @reports.index { it.filename == filename } if idx prev = @reports[idx] @reports[idx] = ValidationReport.new( filename: prev.filename, image_issues: prev.image_issues + image_issues, link_issues: prev.link_issues + link_issues ) else @reports << ValidationReport.new(filename:, image_issues:, link_issues:) end end end |
.print_summary ⇒ Object
検証結果のサマリーを表示する
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 |
# File 'lib/vivlio_starter/cli/pre_process/link_image_validator.rb', line 161 def print_summary reports = @monitor.synchronize { @reports.dup } return if reports.empty? total_missing_image = reports.sum { it.image_issues.count { |i| i.issue_type == :missing } } total_missing_code = reports.sum { it.image_issues.count { |i| i.issue_type == :missing_code } } total_link = reports.sum { it.link_issues.size } if total_missing_image.zero? && total_missing_code.zero? && total_link.zero? Common.log_info('リンク・画像の検証が完了しました(良好な状態です)') return end # --- サマリー集計 --- detail_lines = [] detail_lines << "画像: #{total_missing_image} 件の課題(存在しない画像: #{total_missing_image})" if total_missing_image.positive? detail_lines << "ソースコード: #{total_missing_code} 件の課題(存在しないファイル: #{total_missing_code})" if total_missing_code.positive? if total_link.positive? = reports.sum { it.link_issues.count { |i| i.issue_type == :bare_url } } unreachable = reports.sum { it.link_issues.count { |i| i.issue_type == :unreachable } } dangerous = reports.sum { it.link_issues.count { |i| i.issue_type == :dangerous_scheme } } parts = [] parts << "危険スキーム: #{dangerous}" if dangerous.positive? parts << "リンク切れ: #{unreachable}" if unreachable.positive? parts << "裸 URL: #{}" if .positive? detail_lines << "リンク: #{total_link} 件の問題(#{parts.join(', ')})" end config = resolve_config detail_lines << '外部URL到達性チェック: スキップ(--verify-links で有効化)' unless config[:verify_external_links] Common.log_summary('リンク・画像検証の結果:', detail: detail_lines.join("\n")) # --- 危険スキームの詳細(セキュリティ上の重要度が高いため先頭)--- reports.each do |report| report.link_issues.select { it.issue_type == :dangerous_scheme }.each do |issue| Common.log_warn( "#{issue.filename}:#{issue.line_number} - 危険なスキームを検出しました", detail: "URL: #{issue.url}\n#{issue.}" ) end end # --- リンク切れの詳細 --- reports.each do |report| report.link_issues.select { it.issue_type == :unreachable }.each do |issue| Common.log_error( "#{issue.filename}:#{issue.line_number} - リンク切れを検出しました", detail: "URL: #{issue.url} → #{issue.}" ) end end end |
.record_code_include_error(filename, line_number, code_name) ⇒ Object
コードインクルードエラーをレポートに記録する MarkdownTransformer から呼ばれ、preflight の終了コード判定に反映させる
228 229 230 231 232 233 234 235 236 237 |
# File 'lib/vivlio_starter/cli/pre_process/link_image_validator.rb', line 228 def record_code_include_error(filename, line_number, code_name) issue = ImageIssue.new( filename:, line_number:, image_path: code_name, issue_type: :missing_code ) merge_into_report(filename, image_issues: [issue]) record_to_registry(issue) end |
.reset! ⇒ Object
レポート蓄積をリセットする(ビルド開始時に呼ぶ)
54 55 56 57 58 59 |
# File 'lib/vivlio_starter/cli/pre_process/link_image_validator.rb', line 54 def reset! @monitor.synchronize do @reports = [] @external_urls = [] end end |
.validate(content, filename, source_path: nil, config: resolve_config) ⇒ ValidationReport
リンクと画像をまとめて検証する(単発の検証向けの入口)。 ビルドの前処理は、それぞれを正しい段階で呼ぶために分けて使う。
123 124 125 126 127 |
# File 'lib/vivlio_starter/cli/pre_process/link_image_validator.rb', line 123 def validate(content, filename, source_path: nil, config: resolve_config) image_issues = validate_images(content, filename, source_path:, config:) link_issues = validate_links(content, filename, config:) ValidationReport.new(filename:, image_issues:, link_issues:) end |
.validate_images(content, filename, source_path: nil, config: resolve_config) ⇒ Array<ImageIssue>
画像の存在を検証する。パス正規化とデータ展開のあとに適用すること。
解決済みのパスでないとファイルの有無を判定できないため、この時点の行番号は
原稿とずれている。source_path を渡すと元ファイルから同じ画像を含む行を
引き当てて付け替える(同じ画像を何度も使う原稿では最初の行に丸まる)。
109 110 111 112 113 114 115 116 117 118 |
# File 'lib/vivlio_starter/cli/pre_process/link_image_validator.rb', line 109 def validate_images(content, filename, source_path: nil, config: resolve_config) image_issues = config[:verify_images] ? scan_missing_images(content, filename) : [] source_content = source_path && File.exist?(source_path) ? File.read(source_path, encoding: 'utf-8') : nil image_issues = image_issues.map { correct_line_number(it, source_content) } if source_content image_issues.each { record_to_registry(it) } merge_into_report(filename, image_issues: image_issues) image_issues end |
.validate_links(content, filename, config: resolve_config) ⇒ Array<LinkIssue>
原稿に書かれたリンクを検証する。前処理にかける前の原稿へ適用すること。
裸 URL の対象は著者が原稿へ直に書いたものだけで、前処理が生成する要素
(@qr の <img alt="URL"> など)は含まない。原稿をそのまま見るので
行番号の付け替えが要らない——同じ URL が何度も出てくる原稿でも、
指摘した行がそのまま著者の手元の行になる。
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/vivlio_starter/cli/pre_process/link_image_validator.rb', line 72 def validate_links(content, filename, config: resolve_config) link_issues = config[:verify_bare_urls] ? (content, filename) : [] link_issues.each do |issue| Common.log_warn( "#{issue.filename}:#{issue.line_number} - 裸 URL を検出しました", detail: "URL: #{issue.url}" ) end # セキュリティ検証(11-1): 危険スキームの検出は常時有効 # file:// / javascript: 等は --no-verify でも無効化しない link_issues += scan_dangerous_schemes(content, filename) # 外部 URL チェック用に URL を蓄積(後でバッチ実行) if config[:verify_external_links] urls = extract_external_urls(content, filename) @monitor.synchronize { @external_urls.concat(urls) } end # 章別サマリー用の横断集計へブリッジする(preflight-chapter-summary-spec.md §2.2)。 link_issues.each { record_to_registry(it) } merge_into_report(filename, link_issues: link_issues) link_issues end |