Class: VivlioStarter::CLI::LintCommands::LintRunner
- Inherits:
-
Object
- Object
- VivlioStarter::CLI::LintCommands::LintRunner
- Defined in:
- lib/vivlio_starter/cli/lint.rb
Overview
text:lint 実行ロジックをまとめたランナー
Defined Under Namespace
Classes: TargetResolver
Instance Attribute Summary collapse
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#targets ⇒ Object
readonly
Returns the value of attribute targets.
Instance Method Summary collapse
-
#apply_prose_fixes!(files) ⇒ Array<String>
交ぜ書きの置換を原稿へ適用する(--fix 指定時のみ)。 対比の指摘は自動修正しない(どちらが X するのかは著者しか知らないため)。.
- #call ⇒ Object
- #check_prose(path) ⇒ Object
-
#disabled_rules ⇒ Object
book.yml lint.disabled_rules(ルール ID で丸ごと無効化).
-
#initialize(targets, options) ⇒ LintRunner
constructor
A new instance of LintRunner.
- #print_textlint_aggregated(result) ⇒ Object
-
#prose_allowlist ⇒ Object
config/textlint_allowlist.yml の語で交ぜ書きの指摘を黙らせる。 textlint と同じファイルを読むので、著者が窓口を二度覚えなくて済む。.
-
#run_prose_check(files) ⇒ Object
textlint では扱えない指摘(交ぜ書き・二通りに読める対比)を当てる。 件数は「日本語校正」へ合算する——著者から見れば textlint の指摘と区別する 理由がない。仕様: lint-japanese-prose-rules-spec.md §5.
-
#run_textlint(files) ⇒ Object
textlint 本体を実行して結果サマリーを返す。 出力は常にルール単位の集約表示(textlint --format json を取得して整形)。.
-
#run_textlint_aggregated(files, path_map = {}, suppressed_lines = {}) ⇒ Object
ルール単位で集約した独自表示(--format json で取得して整形).
-
#spellcheck_only? ⇒ Boolean
--spellcheck-only / --textlint-only / --register による実行範囲。 --register はスペルチェック専用の操作なので、暗黙に spellcheck 単独で動く (
--spellcheck-onlyを併記する必要はない)。. - #textlint_exit(status) ⇒ Object
- #textlint_only? ⇒ Boolean
-
#trim_long_vowel? ⇒ Boolean
book.yml lint.trim_long_vowel(末尾長音を足す指摘を抑止:技術者向け文体).
Constructor Details
#initialize(targets, options) ⇒ LintRunner
Returns a new instance of LintRunner.
90 91 92 93 |
# File 'lib/vivlio_starter/cli/lint.rb', line 90 def initialize(targets, ) @targets = Array(targets) @options = () end |
Instance Attribute Details
#options ⇒ Object (readonly)
Returns the value of attribute options.
88 89 90 |
# File 'lib/vivlio_starter/cli/lint.rb', line 88 def @options end |
#targets ⇒ Object (readonly)
Returns the value of attribute targets.
88 89 90 |
# File 'lib/vivlio_starter/cli/lint.rb', line 88 def targets @targets end |
Instance Method Details
#apply_prose_fixes!(files) ⇒ Array<String>
交ぜ書きの置換を原稿へ適用する(--fix 指定時のみ)。 対比の指摘は自動修正しない(どちらが X するのかは著者しか知らないため)。
193 194 195 196 197 198 199 200 201 202 203 204 |
# File 'lib/vivlio_starter/cli/lint.rb', line 193 def apply_prose_fixes!(files) return [] if disabled_rules.include?(Lint::ProseChecker::MAZEGAKI_RULE) files.filter_map do |path| original = File.read(path, encoding: 'UTF-8') fixed = Lint::ProseChecker.fix_mazegaki(original, prose_allowlist) next if fixed == original atomic_write(path, fixed) path end end |
#call ⇒ Object
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/vivlio_starter/cli/lint.rb', line 101 def call ensure_textlint_available! unless spellcheck_only? ensure_config_present! unless spellcheck_only? ensure_support_yaml_files! unless spellcheck_only? files = resolve_targets if files.empty? Common.log_warn('検査対象となる Markdown ファイルが見つかりません。') return 0 end lint_info = { exit: 0, lint_count: 0, fixable_count: 0, fixed_files: [] } prose_info = { exit: 0, prose_count: 0, fixed_files: [] } spell_info = { exit: 0, spell_count: 0 } unless spellcheck_only? # 交ぜ書きの置換を先に済ませてから textlint を走らせる。逆順にすると # textlint が見る原稿と、置換後に残る原稿が食い違う。 prose_fixed = [:fix] ? apply_prose_fixes!(files) : [] lint_info = run_textlint(files) prose_info = run_prose_check(files).merge(fixed_files: prose_fixed) end spell_info = run_spellcheck(files) unless textlint_only? print_combined_summary(lint_info, prose_info, spell_info) [lint_info[:exit], prose_info[:exit], spell_info[:exit]].max rescue LintError => e Common.log_error(e.) 1 end |
#check_prose(path) ⇒ Object
206 207 208 |
# File 'lib/vivlio_starter/cli/lint.rb', line 206 def check_prose(path) Lint::ProseChecker.check(path, disabled_rules: disabled_rules, allowlist: prose_allowlist) end |
#disabled_rules ⇒ Object
book.yml lint.disabled_rules(ルール ID で丸ごと無効化)
218 219 220 |
# File 'lib/vivlio_starter/cli/lint.rb', line 218 def disabled_rules Array(Common::CONFIG.lint.disabled_rules).map(&:to_s) end |
#print_textlint_aggregated(result) ⇒ Object
227 228 229 230 231 232 233 234 235 236 |
# File 'lib/vivlio_starter/cli/lint.rb', line 227 def print_textlint_aggregated(result) result[:files].each do |file| Common.log_always "📄 #{file[:path]} (textlint)" file[:rows].each do |row| Common.log_always format(' %3d件 %s', row[:count], row[:label]) Common.log_always format(' 行: %s', row[:lines]) end Common.log_always '' end end |
#prose_allowlist ⇒ Object
config/textlint_allowlist.yml の語で交ぜ書きの指摘を黙らせる。 textlint と同じファイルを読むので、著者が窓口を二度覚えなくて済む。
212 213 214 215 |
# File 'lib/vivlio_starter/cli/lint.rb', line 212 def prose_allowlist @prose_allowlist ||= Lint::ProseChecker.allowlist_from(Common.resolve_path_from_root(TEXTLINT_ALLOWLIST_RELATIVE)) end |
#run_prose_check(files) ⇒ Object
textlint では扱えない指摘(交ぜ書き・二通りに読める対比)を当てる。 件数は「日本語校正」へ合算する——著者から見れば textlint の指摘と区別する 理由がない。仕様: lint-japanese-prose-rules-spec.md §5
179 180 181 182 183 184 185 186 187 188 |
# File 'lib/vivlio_starter/cli/lint.rb', line 179 def run_prose_check(files) findings_by_file = files.to_h { [it, check_prose(it)] } .reject { |_path, findings| findings.empty? } Lint::ProseChecker.print_errors(findings_by_file) all = findings_by_file.values.flatten { exit: all.empty? ? 0 : 1, prose_count: all.size, fixable_count: all.count { it.rule == Lint::ProseChecker::MAZEGAKI_RULE } } end |
#run_textlint(files) ⇒ Object
textlint 本体を実行して結果サマリーを返す。 出力は常にルール単位の集約表示(textlint --format json を取得して整形)。
--fix 指定時は「修正パス → 解析パス」の 2 段構成を採る。修正パスは記法ガードを 通さない一時ファイルを textlint に直させて原稿へ書き戻し、解析パスはガード済みの 一時ファイルから残存指摘を集める。ガードによる記法の中和は非可逆なので、 ガード済みの内容を原稿へ書き戻すことはできない(両立させるための 2 パス)。 仕様: lint-notation-guard-spec.md §2.3
140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/vivlio_starter/cli/lint.rb', line 140 def run_textlint(files) fixed_files = [:fix] ? apply_textlint_fixes!(files) : [] converted_files = convert_vs_lint_comments(files) # textlint は一時ファイルを検査するため、出力の一時パスを元ファイル名へ戻すマップ path_map = files.zip(converted_files).to_h { |orig, tmp| [File.(tmp), orig] } hushed = suppressed_lines_map(files, converted_files) run_textlint_aggregated(converted_files, path_map, hushed).merge(fixed_files: fixed_files) ensure cleanup_temp_files(converted_files) if converted_files @runtime_config_tmp&.unlink end |
#run_textlint_aggregated(files, path_map = {}, suppressed_lines = {}) ⇒ Object
ルール単位で集約した独自表示(--format json で取得して整形)
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/vivlio_starter/cli/lint.rb', line 154 def run_textlint_aggregated(files, path_map = {}, suppressed_lines = {}) command = build_command(files, format: 'json') stdout, stderr, status = Open3.capture3(*command) $stderr.print(stderr) unless stderr.nil? || stderr.empty? result = TextlintFormatter.aggregate_json( stdout, disabled_rules: disabled_rules, trim_long_vowel: trim_long_vowel?, suppressed_lines: suppressed_lines ) if result.nil? # JSON 解釈に失敗(textlint 自体のエラー等)。生出力をそのまま見せる。 $stdout.print(stdout) unless stdout.nil? || stdout.empty? return { exit: textlint_exit(status), lint_count: 0, fixable_count: 0 } end # 一時ファイルのパスを元ファイル名へ戻す result[:files].each { |f| f[:path] = path_map[File.(f[:path])] || f[:path] } print_textlint_aggregated(result) # 無効化で除外した分は問題数に数えない(残り 0 なら成功扱い) { exit: result[:total].positive? ? 1 : 0, lint_count: result[:total], fixable_count: result[:fixable] } end |
#spellcheck_only? ⇒ Boolean
--spellcheck-only / --textlint-only / --register による実行範囲。
--register はスペルチェック専用の操作なので、暗黙に spellcheck 単独で動く
(--spellcheck-only を併記する必要はない)。
98 |
# File 'lib/vivlio_starter/cli/lint.rb', line 98 def spellcheck_only? = [:register] || [:spellcheck_only] |
#textlint_exit(status) ⇒ Object
238 |
# File 'lib/vivlio_starter/cli/lint.rb', line 238 def textlint_exit(status) = status.success? ? 0 : (status.exitstatus || 1) |
#textlint_only? ⇒ Boolean
99 |
# File 'lib/vivlio_starter/cli/lint.rb', line 99 def textlint_only? = ![:register] && [:textlint_only] |