Module: VivlioStarter::CLI::Lint::Tokenizer
- Defined in:
- lib/vivlio_starter/cli/lint/tokenizer.rb
Overview
Markdownファイルから英単語トークンを抽出する
Constant Summary collapse
- FRONTMATTER_SEP =
/^---\s*$/- VS_LINT_DISABLE =
vs-lint コメント記法の定義
/^\s*<!--\s*vs-lint-disable\s*-->\s*$/- VS_LINT_ENABLE =
/^\s*<!--\s*vs-lint-enable\s*-->\s*$/- VS_LINT_DISABLE_NEXT_LINE =
/^\s*<!--\s*vs-lint-disable-next-line\s*-->\s*$/
Class Method Summary collapse
-
.build_excluded_lines(content) ⇒ Array(Set<Integer>, Integer?)
vs-lint コメントに基づいて除外すべき行番号のセットを構築する.
-
.code_fence_lines(content) ⇒ Object
コード(フェンス区切り行・内容行)とみなす行番号の集合を Masking で判定する。.
-
.extract_words(line) ⇒ Array<String>
抽出された英単語の配列.
-
.tokenize(content, check_code_blocks: false, path: nil) ⇒ Array<[String, Integer]>
[word, line_no] のペア配列.
-
.warn_unclosed_disable(path, opened_at) ⇒ Object
vs-lint-disable が閉じられないままファイル末尾に達した場合に警告を出す。 著者が誤って enable を書き忘れたケースを検知するためのガード。.
Class Method Details
.build_excluded_lines(content) ⇒ Array(Set<Integer>, Integer?)
vs-lint コメントに基づいて除外すべき行番号のセットを構築する
コード領域の中は見ない。 校正の使い方を解説する原稿は、フェンスの中へ
<!-- vs-lint-disable --> を書き写す。それを本物の指示として解釈すると、
例示のつもりの 1 行がファイル末尾までの抑止になる(実測: ```markdown の中に
閉じない disable を置くと、その下の本文の綴り誤りが検出されなくなった)。
記法かどうかの判定は Masking へ委ね、ProseChecker と同じ扱いに揃える。
90 91 92 93 94 95 96 97 98 99 100 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 |
# File 'lib/vivlio_starter/cli/lint/tokenizer.rb', line 90 def build_excluded_lines(content) excluded_lines = Set.new disable_opened_at = nil prose = Set.new Masking.each_prose_line(content) { |_line, lineno| prose << lineno } line_no = 0 content.each_line do |line| line_no += 1 next unless prose.include?(line_no) # vs-lint-disable コメント行自体を除外 if line.match?(VS_LINT_DISABLE) disable_opened_at ||= line_no excluded_lines.add(line_no) next end # vs-lint-enable コメント行自体を除外 if line.match?(VS_LINT_ENABLE) disable_opened_at = nil excluded_lines.add(line_no) next end # vs-lint-disable-next-line コメント行自体を除外し、次の行も除外 if line.match?(VS_LINT_DISABLE_NEXT_LINE) excluded_lines.add(line_no) excluded_lines.add(line_no + 1) next end # disable ブロック内の行を除外 excluded_lines.add(line_no) if disable_opened_at end [excluded_lines, disable_opened_at] end |
.code_fence_lines(content) ⇒ Object
コード(フェンス区切り行・内容行)とみなす行番号の集合を Masking で判定する。
72 73 74 75 76 77 |
# File 'lib/vivlio_starter/cli/lint/tokenizer.rb', line 72 def code_fence_lines(content) prose = Set.new Masking.each_prose_line(content) { |_line, lineno| prose << lineno } total = content.each_line.count (1..total).reject { prose.include?(it) }.to_set end |
.extract_words(line) ⇒ Array<String>
Returns 抽出された英単語の配列.
148 149 150 151 152 153 154 155 156 157 158 159 160 |
# File 'lib/vivlio_starter/cli/lint/tokenizer.rb', line 148 def extract_words(line) cleaned = line.dup cleaned.gsub!(/`[^`]*`/, ' ') # インラインコードを除去 cleaned.gsub!(/<[^>]+>/, ' ') # HTMLタグを除去 cleaned.gsub!(/\{[^}]*\}/, ' ') # Vivliostyle拡張記法 {.aki} 等 cleaned.gsub!(/(?<![A-Za-z0-9_])@[A-Za-z][A-Za-z0-9-]*/, ' ') # 相互参照ラベル @id(メールは除外) cleaned.gsub!(/!?\[([^\]]*)\]\([^)]*\)/, '\1') # Markdownリンク・画像 cleaned.gsub!(/!?\[([^\]]*)\]\[[^\]]*\]/, '\1') # 参照リンク cleaned.gsub!(%r{https?://\S+}, ' ') # URLを除去 cleaned.gsub!(/^#+\s*/, '') # 見出し記号を除去 cleaned.scan(/[a-zA-Z]+(?:-[a-zA-Z]+)*/).select { it.length >= 2 } end |
.tokenize(content, check_code_blocks: false, path: nil) ⇒ Array<[String, Integer]>
Returns [word, line_no] のペア配列.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/vivlio_starter/cli/lint/tokenizer.rb', line 25 def tokenize(content, check_code_blocks: false, path: nil) # VFM 記法(showcase の座標行・クラス属性など)を先に中和する。textlint 側と # 同じ NotationGuard を通すことで、記法の判定が lint 全体で一本化される。 # 行数は保存されるため、以降の行番号は原稿のものと一致したままになる。 content = NotationGuard.strip_notation(content) tokens = [] in_frontmatter = false line_no = 0 # vs-lint コメントによる除外行番号セットを構築 excluded_lines, unclosed_disable_at = build_excluded_lines(content) warn_unclosed_disable(path, unclosed_disable_at) if unclosed_disable_at # コードフェンス行の集合を Masking(唯一の実装)で判定する。 # 従来の /^```/ 単純トグルと異なり、可変長フェンス(```/````/~~~)と # 入れ子・```include: 除外に追従するため、入れ子フェンスで本文を誤って # コード扱いしなくなる。check_code_blocks 時はコードも検査対象に含める。 code_lines = check_code_blocks ? Set.new : code_fence_lines(content) content.each_line do |line| line_no += 1 # YAMLフロントマター(先頭 --- 〜 --- )をスキップ if line_no == 1 && line.match?(FRONTMATTER_SEP) in_frontmatter = true next end if in_frontmatter in_frontmatter = false if line.match?(FRONTMATTER_SEP) next end # コードブロック内のスキップ next if code_lines.include?(line_no) # vs-lint コメントによる除外 next if excluded_lines.include?(line_no) extract_words(line).each { |word| tokens << [word, line_no] } end tokens end |
.warn_unclosed_disable(path, opened_at) ⇒ Object
vs-lint-disable が閉じられないままファイル末尾に達した場合に警告を出す。 著者が誤って enable を書き忘れたケースを検知するためのガード。
Kernel#warn を使ってはならない。 bin/vs は起動時に RUBYOPT=-W0 を
付けて自身を再実行しており、-W0 は Kernel#warn の出力を丸ごと捨てる。
そのため vs lint 経由ではこの警告が一度も著者へ届いていなかった
(2026-08-18 に判明。ライブラリを直接叩くテストでは出るので気づきにくい)。
Common.log_warn を通すことで 🟡 の体裁とログレベル制御が他の警告と揃う
(cli-warning-delivery-spec.md §5.1)。
140 141 142 143 144 |
# File 'lib/vivlio_starter/cli/lint/tokenizer.rb', line 140 def warn_unclosed_disable(path, opened_at) location = path ? "#{path}:#{opened_at}" : "line #{opened_at}" Common.log_warn("[vs-lint] #{location} の <!-- vs-lint-disable --> が " \ '<!-- vs-lint-enable --> で閉じられていません。ファイル末尾まで lint が無効化されます。') end |