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 コメントに基づいて除外すべき行番号のセットを構築する
82 83 84 85 86 87 88 89 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 |
# File 'lib/vivlio_starter/cli/lint/tokenizer.rb', line 82 def build_excluded_lines(content) excluded_lines = Set.new disable_opened_at = nil line_no = 0 content.each_line do |line| line_no += 1 # 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 で判定する。
71 72 73 74 75 76 |
# File 'lib/vivlio_starter/cli/lint/tokenizer.rb', line 71 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 抽出された英単語の配列.
130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/vivlio_starter/cli/lint/tokenizer.rb', line 130 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] のペア配列.
24 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 |
# File 'lib/vivlio_starter/cli/lint/tokenizer.rb', line 24 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 を書き忘れたケースを検知するためのガード。
122 123 124 125 126 |
# File 'lib/vivlio_starter/cli/lint/tokenizer.rb', line 122 def warn_unclosed_disable(path, opened_at) location = path ? "#{path}:#{opened_at}" : "line #{opened_at}" warn "[vs-lint] 警告: #{location} の <!-- vs-lint-disable --> が " \ '<!-- vs-lint-enable --> で閉じられていません。ファイル末尾まで lint が無効化されます。' end |