i18n-tasks 1.0.12 → 1.0.14
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.
- checksums.yaml +4 -4
- data/README.md +85 -2
- data/Rakefile +1 -1
- data/config/locales/en.yml +11 -4
- data/config/locales/ru.yml +11 -4
- data/i18n-tasks.gemspec +5 -5
- data/lib/i18n/tasks/cli.rb +8 -8
- data/lib/i18n/tasks/command/commands/data.rb +14 -0
- data/lib/i18n/tasks/command/commands/missing.rb +2 -2
- data/lib/i18n/tasks/command/options/common.rb +1 -1
- data/lib/i18n/tasks/configuration.rb +3 -1
- data/lib/i18n/tasks/data/adapter/yaml_adapter.rb +7 -1
- data/lib/i18n/tasks/data/file_system_base.rb +5 -0
- data/lib/i18n/tasks/data/router/isolating_router.rb +146 -0
- data/lib/i18n/tasks/data/tree/siblings.rb +2 -2
- data/lib/i18n/tasks/data/tree/traversal.rb +2 -2
- data/lib/i18n/tasks/interpolations.rb +1 -1
- data/lib/i18n/tasks/key_pattern_matching.rb +5 -3
- data/lib/i18n/tasks/references.rb +3 -3
- data/lib/i18n/tasks/reports/base.rb +1 -1
- data/lib/i18n/tasks/reports/terminal.rb +7 -1
- data/lib/i18n/tasks/scanners/ast_matchers/default_i18n_subject_matcher.rb +26 -0
- data/lib/i18n/tasks/scanners/ast_matchers/message_receivers_matcher.rb +4 -4
- data/lib/i18n/tasks/scanners/erb_ast_scanner.rb +55 -25
- data/lib/i18n/tasks/scanners/pattern_scanner.rb +1 -1
- data/lib/i18n/tasks/scanners/relative_keys.rb +1 -1
- data/lib/i18n/tasks/scanners/ruby_ast_scanner.rb +3 -1
- data/lib/i18n/tasks/split_key.rb +30 -47
- data/lib/i18n/tasks/translation.rb +4 -1
- data/lib/i18n/tasks/translators/base_translator.rb +22 -11
- data/lib/i18n/tasks/translators/deepl_translator.rb +58 -9
- data/lib/i18n/tasks/translators/google_translator.rb +28 -13
- data/lib/i18n/tasks/translators/openai_translator.rb +118 -0
- data/lib/i18n/tasks/used_keys.rb +5 -5
- data/lib/i18n/tasks/version.rb +1 -1
- data/templates/config/i18n-tasks.yml +28 -3
- data/templates/minitest/i18n_test.rb +6 -6
- metadata +40 -30
- data/lib/i18n/tasks/scanners/erb_ast_processor.rb +0 -74
@@ -0,0 +1,118 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'i18n/tasks/translators/base_translator'
|
4
|
+
require 'active_support/core_ext/string/filters'
|
5
|
+
|
6
|
+
module I18n::Tasks::Translators
|
7
|
+
class OpenAiTranslator < BaseTranslator
|
8
|
+
# max allowed texts per request
|
9
|
+
BATCH_SIZE = 50
|
10
|
+
DEFAULT_SYSTEM_PROMPT = <<~PROMPT.squish
|
11
|
+
You are a professional translator that translates content from the %{from} locale
|
12
|
+
to the %{to} locale in an i18n locale array.
|
13
|
+
|
14
|
+
The array has a structured format and contains multiple strings. Your task is to translate
|
15
|
+
each of these strings and create a new array with the translated strings.
|
16
|
+
|
17
|
+
HTML markups (enclosed in < and > characters) must not be changed under any circumstance.
|
18
|
+
Variables (starting with %%{ and ending with }) must not be changed under any circumstance.
|
19
|
+
|
20
|
+
Keep in mind the context of all the strings for a more accurate translation.
|
21
|
+
PROMPT
|
22
|
+
|
23
|
+
def initialize(*)
|
24
|
+
begin
|
25
|
+
require 'openai'
|
26
|
+
rescue LoadError
|
27
|
+
raise ::I18n::Tasks::CommandError, "Add gem 'ruby-openai' to your Gemfile to use this command"
|
28
|
+
end
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
def options_for_translate_values(from:, to:, **options)
|
33
|
+
options.merge(
|
34
|
+
from: from,
|
35
|
+
to: to
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def options_for_html
|
40
|
+
{}
|
41
|
+
end
|
42
|
+
|
43
|
+
def options_for_plain
|
44
|
+
{}
|
45
|
+
end
|
46
|
+
|
47
|
+
def no_results_error_message
|
48
|
+
I18n.t('i18n_tasks.openai_translate.errors.no_results')
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def translator
|
54
|
+
@translator ||= OpenAI::Client.new(access_token: api_key)
|
55
|
+
end
|
56
|
+
|
57
|
+
def api_key
|
58
|
+
@api_key ||= begin
|
59
|
+
key = @i18n_tasks.translation_config[:openai_api_key]
|
60
|
+
fail ::I18n::Tasks::CommandError, I18n.t('i18n_tasks.openai_translate.errors.no_api_key') if key.blank?
|
61
|
+
|
62
|
+
key
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def model
|
67
|
+
@model ||= @i18n_tasks.translation_config[:openai_model].presence || 'gpt-3.5-turbo'
|
68
|
+
end
|
69
|
+
|
70
|
+
def system_prompt
|
71
|
+
@system_prompt ||= @i18n_tasks.translation_config[:openai_system_prompt].presence || DEFAULT_SYSTEM_PROMPT
|
72
|
+
end
|
73
|
+
|
74
|
+
def translate_values(list, from:, to:)
|
75
|
+
results = []
|
76
|
+
|
77
|
+
list.each_slice(BATCH_SIZE) do |batch|
|
78
|
+
translations = translate(batch, from, to)
|
79
|
+
|
80
|
+
results << JSON.parse(translations)
|
81
|
+
end
|
82
|
+
|
83
|
+
results.flatten
|
84
|
+
end
|
85
|
+
|
86
|
+
def translate(values, from, to)
|
87
|
+
messages = [
|
88
|
+
{
|
89
|
+
role: 'system',
|
90
|
+
content: format(system_prompt, from: from, to: to)
|
91
|
+
},
|
92
|
+
{
|
93
|
+
role: 'user',
|
94
|
+
content: "Translate this array: \n\n\n"
|
95
|
+
},
|
96
|
+
{
|
97
|
+
role: 'user',
|
98
|
+
content: values.to_json
|
99
|
+
}
|
100
|
+
]
|
101
|
+
|
102
|
+
response = translator.chat(
|
103
|
+
parameters: {
|
104
|
+
model: model,
|
105
|
+
messages: messages,
|
106
|
+
temperature: 0.0
|
107
|
+
}
|
108
|
+
)
|
109
|
+
|
110
|
+
translations = response.dig('choices', 0, 'message', 'content')
|
111
|
+
error = response['error']
|
112
|
+
|
113
|
+
fail "AI error: #{error}" if error.present?
|
114
|
+
|
115
|
+
translations
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
data/lib/i18n/tasks/used_keys.rb
CHANGED
@@ -21,15 +21,15 @@ module I18n::Tasks
|
|
21
21
|
relative_roots: %w[app/controllers app/helpers app/mailers app/presenters app/views].freeze,
|
22
22
|
scanners: [
|
23
23
|
['::I18n::Tasks::Scanners::RubyAstScanner', { only: %w[*.rb] }],
|
24
|
-
['::I18n::Tasks::Scanners::ErbAstScanner', { only: %w[*.erb] }],
|
25
|
-
['::I18n::Tasks::Scanners::PatternWithScopeScanner', { exclude: %w[*.erb *.rb] }]
|
24
|
+
['::I18n::Tasks::Scanners::ErbAstScanner', { only: %w[*.html.erb] }],
|
25
|
+
['::I18n::Tasks::Scanners::PatternWithScopeScanner', { exclude: %w[*.html.erb *.rb] }]
|
26
26
|
],
|
27
27
|
ast_matchers: [],
|
28
28
|
strict: true
|
29
29
|
}.freeze
|
30
30
|
|
31
|
-
ALWAYS_EXCLUDE = %w[*.jpg *.jpeg *.png *.gif *.svg *.ico *.eot *.otf *.ttf *.woff *.woff2 *.pdf *.css *.sass *.scss
|
32
|
-
*.yml *.json *.zip *.tar.gz *.swf *.flv *.mp3 *.wav *.flac *.webm *.mp4 *.ogg *.opus
|
31
|
+
ALWAYS_EXCLUDE = %w[*.jpg *.jpeg *.png *.gif *.svg *.ico *.eot *.otf *.ttf *.woff *.woff2 *.pdf *.css *.sass *.scss
|
32
|
+
*.less *.yml *.json *.zip *.tar.gz *.swf *.flv *.mp3 *.wav *.flac *.webm *.mp4 *.ogg *.opus
|
33
33
|
*.webp *.map *.xlsx].freeze
|
34
34
|
|
35
35
|
# Find all keys in the source and return a forest with the keys in absolute form and their occurrences.
|
@@ -142,7 +142,7 @@ module I18n::Tasks
|
|
142
142
|
|
143
143
|
# keys in the source that end with a ., e.g. t("category.#{ cat.i18n_key }") or t("category." + category.key)
|
144
144
|
# @param [String] replacement for interpolated values.
|
145
|
-
def expr_key_re(replacement: '
|
145
|
+
def expr_key_re(replacement: '*:')
|
146
146
|
@expr_key_re ||= begin
|
147
147
|
# disallow patterns with no keys
|
148
148
|
ignore_pattern_re = /\A[.#{replacement}]*\z/
|
data/lib/i18n/tasks/version.rb
CHANGED
@@ -13,7 +13,7 @@ data:
|
|
13
13
|
## Provide a custom adapter:
|
14
14
|
# adapter: I18n::Tasks::Data::FileSystem
|
15
15
|
|
16
|
-
# Locale files or `
|
16
|
+
# Locale files or `Dir.glob` patterns where translations are read from:
|
17
17
|
read:
|
18
18
|
## Default:
|
19
19
|
# - config/locales/%{locale}.yml
|
@@ -52,7 +52,7 @@ data:
|
|
52
52
|
|
53
53
|
# Find translate calls
|
54
54
|
search:
|
55
|
-
## Paths or `
|
55
|
+
## Paths or `Find.find` patterns to search in:
|
56
56
|
# paths:
|
57
57
|
# - app/
|
58
58
|
|
@@ -92,9 +92,13 @@ search:
|
|
92
92
|
## - RailsModelMatcher
|
93
93
|
## Matches ActiveRecord translations like
|
94
94
|
## User.human_attribute_name(:email) and User.model_name.human
|
95
|
+
## - DefaultI18nSubjectMatcher
|
96
|
+
## Matches ActionMailer's default_i18n_subject method
|
95
97
|
##
|
96
98
|
## To implement your own, please see `I18n::Tasks::Scanners::AstMatchers::BaseMatcher`.
|
97
|
-
|
99
|
+
# ast_matchers:
|
100
|
+
# - 'I18n::Tasks::Scanners::AstMatchers::RailsModelMatcher'
|
101
|
+
# - 'I18n::Tasks::Scanners::AstMatchers::DefaultI18nSubjectMatcher'
|
98
102
|
|
99
103
|
## Multiple scanners can be used. Their results are merged.
|
100
104
|
## The options specified above are passed down to each scanner. Per-scanner options can be specified as well.
|
@@ -110,6 +114,27 @@ search:
|
|
110
114
|
# deepl_api_key: "48E92789-57A3-466A-9959-1A1A1A1A1A1A"
|
111
115
|
# # deepl_host: "https://api.deepl.com"
|
112
116
|
# # deepl_version: "v2"
|
117
|
+
# # deepl_glossary_ids:
|
118
|
+
# # - f28106eb-0e06-489e-82c6-8215d6f95089
|
119
|
+
# # - 2c6415be-1852-4f54-9e1b-d800463496b4
|
120
|
+
# # add additional options to the DeepL.translate call: https://www.deepl.com/docs-api/translate-text/translate-text/
|
121
|
+
# deepl_options:
|
122
|
+
# formality: prefer_less
|
123
|
+
# # OpenAI
|
124
|
+
# openai_api_key: "sk-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
|
125
|
+
# # openai_model: "gpt-3.5-turbo" # see https://platform.openai.com/docs/models
|
126
|
+
# # may contain `%{from}` and `%{to}`, which will be replaced by source and target locale codes, respectively (using `Kernel.format`)
|
127
|
+
# # openai_system_prompt: >-
|
128
|
+
# # You are a professional translator that translates content from the %{from} locale
|
129
|
+
# # to the %{to} locale in an i18n locale array.
|
130
|
+
# #
|
131
|
+
# # The array has a structured format and contains multiple strings. Your task is to translate
|
132
|
+
# # each of these strings and create a new array with the translated strings.
|
133
|
+
# #
|
134
|
+
# # HTML markups (enclosed in < and > characters) must not be changed under any circumstance.
|
135
|
+
# # Variables (starting with %%{ and ending with }) must not be changed under any circumstance.
|
136
|
+
# #
|
137
|
+
# # Keep in mind the context of all the strings for a more accurate translation.
|
113
138
|
|
114
139
|
## Do not consider these keys missing:
|
115
140
|
# ignore_missing:
|
@@ -5,18 +5,18 @@ require 'i18n/tasks'
|
|
5
5
|
class I18nTest < ActiveSupport::TestCase
|
6
6
|
def setup
|
7
7
|
@i18n = I18n::Tasks::BaseTask.new
|
8
|
-
@missing_keys = @i18n.missing_keys
|
9
|
-
@unused_keys = @i18n.unused_keys
|
10
8
|
end
|
11
9
|
|
12
10
|
def test_no_missing_keys
|
13
|
-
|
14
|
-
|
11
|
+
missing_keys = @i18n.missing_keys
|
12
|
+
assert_empty missing_keys,
|
13
|
+
"Missing #{missing_keys.leaves.count} i18n keys, run `i18n-tasks missing' to show them"
|
15
14
|
end
|
16
15
|
|
17
16
|
def test_no_unused_keys
|
18
|
-
|
19
|
-
|
17
|
+
unused_keys = @i18n.unused_keys
|
18
|
+
assert_empty unused_keys,
|
19
|
+
"#{unused_keys.leaves.count} unused i18n keys, run `i18n-tasks unused' to show them"
|
20
20
|
end
|
21
21
|
|
22
22
|
def test_files_are_normalized
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: i18n-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.14
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- glebm
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-05-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -38,26 +38,6 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 2.1.0
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: better_html
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '1.0'
|
48
|
-
- - "<"
|
49
|
-
- !ruby/object:Gem::Version
|
50
|
-
version: '3.0'
|
51
|
-
type: :runtime
|
52
|
-
prerelease: false
|
53
|
-
version_requirements: !ruby/object:Gem::Requirement
|
54
|
-
requirements:
|
55
|
-
- - ">="
|
56
|
-
- !ruby/object:Gem::Version
|
57
|
-
version: '1.0'
|
58
|
-
- - "<"
|
59
|
-
- !ruby/object:Gem::Version
|
60
|
-
version: '3.0'
|
61
41
|
- !ruby/object:Gem::Dependency
|
62
42
|
name: erubi
|
63
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -106,14 +86,14 @@ dependencies:
|
|
106
86
|
requirements:
|
107
87
|
- - ">="
|
108
88
|
- !ruby/object:Gem::Version
|
109
|
-
version: 2.2.
|
89
|
+
version: 3.2.2.1
|
110
90
|
type: :runtime
|
111
91
|
prerelease: false
|
112
92
|
version_requirements: !ruby/object:Gem::Requirement
|
113
93
|
requirements:
|
114
94
|
- - ">="
|
115
95
|
- !ruby/object:Gem::Version
|
116
|
-
version: 2.2.
|
96
|
+
version: 3.2.2.1
|
117
97
|
- !ruby/object:Gem::Dependency
|
118
98
|
name: rails-i18n
|
119
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -230,14 +210,42 @@ dependencies:
|
|
230
210
|
requirements:
|
231
211
|
- - "~>"
|
232
212
|
- !ruby/object:Gem::Version
|
233
|
-
version: 1.
|
213
|
+
version: 1.50.1
|
214
|
+
type: :development
|
215
|
+
prerelease: false
|
216
|
+
version_requirements: !ruby/object:Gem::Requirement
|
217
|
+
requirements:
|
218
|
+
- - "~>"
|
219
|
+
- !ruby/object:Gem::Version
|
220
|
+
version: 1.50.1
|
221
|
+
- !ruby/object:Gem::Dependency
|
222
|
+
name: rubocop-rake
|
223
|
+
requirement: !ruby/object:Gem::Requirement
|
224
|
+
requirements:
|
225
|
+
- - "~>"
|
226
|
+
- !ruby/object:Gem::Version
|
227
|
+
version: 0.6.0
|
228
|
+
type: :development
|
229
|
+
prerelease: false
|
230
|
+
version_requirements: !ruby/object:Gem::Requirement
|
231
|
+
requirements:
|
232
|
+
- - "~>"
|
233
|
+
- !ruby/object:Gem::Version
|
234
|
+
version: 0.6.0
|
235
|
+
- !ruby/object:Gem::Dependency
|
236
|
+
name: rubocop-rspec
|
237
|
+
requirement: !ruby/object:Gem::Requirement
|
238
|
+
requirements:
|
239
|
+
- - "~>"
|
240
|
+
- !ruby/object:Gem::Version
|
241
|
+
version: 2.19.0
|
234
242
|
type: :development
|
235
243
|
prerelease: false
|
236
244
|
version_requirements: !ruby/object:Gem::Requirement
|
237
245
|
requirements:
|
238
246
|
- - "~>"
|
239
247
|
- !ruby/object:Gem::Version
|
240
|
-
version:
|
248
|
+
version: 2.19.0
|
241
249
|
- !ruby/object:Gem::Dependency
|
242
250
|
name: simplecov
|
243
251
|
requirement: !ruby/object:Gem::Requirement
|
@@ -360,6 +368,7 @@ files:
|
|
360
368
|
- lib/i18n/tasks/data/file_system.rb
|
361
369
|
- lib/i18n/tasks/data/file_system_base.rb
|
362
370
|
- lib/i18n/tasks/data/router/conservative_router.rb
|
371
|
+
- lib/i18n/tasks/data/router/isolating_router.rb
|
363
372
|
- lib/i18n/tasks/data/router/pattern_router.rb
|
364
373
|
- lib/i18n/tasks/data/tree/node.rb
|
365
374
|
- lib/i18n/tasks/data/tree/nodes.rb
|
@@ -378,9 +387,9 @@ files:
|
|
378
387
|
- lib/i18n/tasks/reports/base.rb
|
379
388
|
- lib/i18n/tasks/reports/terminal.rb
|
380
389
|
- lib/i18n/tasks/scanners/ast_matchers/base_matcher.rb
|
390
|
+
- lib/i18n/tasks/scanners/ast_matchers/default_i18n_subject_matcher.rb
|
381
391
|
- lib/i18n/tasks/scanners/ast_matchers/message_receivers_matcher.rb
|
382
392
|
- lib/i18n/tasks/scanners/ast_matchers/rails_model_matcher.rb
|
383
|
-
- lib/i18n/tasks/scanners/erb_ast_processor.rb
|
384
393
|
- lib/i18n/tasks/scanners/erb_ast_scanner.rb
|
385
394
|
- lib/i18n/tasks/scanners/file_scanner.rb
|
386
395
|
- lib/i18n/tasks/scanners/files/caching_file_finder.rb
|
@@ -408,6 +417,7 @@ files:
|
|
408
417
|
- lib/i18n/tasks/translators/base_translator.rb
|
409
418
|
- lib/i18n/tasks/translators/deepl_translator.rb
|
410
419
|
- lib/i18n/tasks/translators/google_translator.rb
|
420
|
+
- lib/i18n/tasks/translators/openai_translator.rb
|
411
421
|
- lib/i18n/tasks/translators/yandex_translator.rb
|
412
422
|
- lib/i18n/tasks/unused_keys.rb
|
413
423
|
- lib/i18n/tasks/used_keys.rb
|
@@ -445,8 +455,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
445
455
|
- !ruby/object:Gem::Version
|
446
456
|
version: '0'
|
447
457
|
requirements: []
|
448
|
-
rubygems_version: 3.
|
449
|
-
signing_key:
|
458
|
+
rubygems_version: 3.5.3
|
459
|
+
signing_key:
|
450
460
|
specification_version: 4
|
451
461
|
summary: Manage localization and translation with the awesome power of static analysis
|
452
462
|
test_files: []
|
@@ -1,74 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'ast'
|
4
|
-
require 'set'
|
5
|
-
require 'i18n/tasks/scanners/local_ruby_parser'
|
6
|
-
|
7
|
-
module I18n::Tasks::Scanners
|
8
|
-
class ErbAstProcessor
|
9
|
-
include AST::Processor::Mixin
|
10
|
-
def initialize
|
11
|
-
super()
|
12
|
-
@ruby_parser = LocalRubyParser.new(ignore_blocks: true)
|
13
|
-
@comments = []
|
14
|
-
end
|
15
|
-
|
16
|
-
def process_and_extract_comments(ast)
|
17
|
-
result = process(ast)
|
18
|
-
[result, @comments]
|
19
|
-
end
|
20
|
-
|
21
|
-
def on_code(node)
|
22
|
-
parsed, comments = @ruby_parser.parse(
|
23
|
-
node.children[0],
|
24
|
-
location: node.location
|
25
|
-
)
|
26
|
-
@comments.concat(comments)
|
27
|
-
|
28
|
-
unless parsed.nil?
|
29
|
-
parsed = parsed.updated(
|
30
|
-
nil,
|
31
|
-
parsed.children.map { |child| node?(child) ? process(child) : child }
|
32
|
-
)
|
33
|
-
node = node.updated(:send, parsed)
|
34
|
-
end
|
35
|
-
node
|
36
|
-
end
|
37
|
-
|
38
|
-
# @param node [::Parser::AST::Node]
|
39
|
-
# @return [::Parser::AST::Node]
|
40
|
-
def handler_missing(node)
|
41
|
-
node = handle_comment(node)
|
42
|
-
return if node.nil?
|
43
|
-
|
44
|
-
node.updated(
|
45
|
-
nil,
|
46
|
-
node.children.map { |child| node?(child) ? process(child) : child }
|
47
|
-
)
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
# Convert ERB-comments to ::Parser::Source::Comment and skip processing node
|
53
|
-
#
|
54
|
-
# @param node Parser::AST::Node Potential comment node
|
55
|
-
# @return Parser::AST::Node or nil
|
56
|
-
def handle_comment(node)
|
57
|
-
if node.type == :erb && node.children.size == 4 &&
|
58
|
-
node.children[0]&.type == :indicator && node.children[0].children[0] == '#' &&
|
59
|
-
node.children[2]&.type == :code
|
60
|
-
|
61
|
-
# Do not continue parsing this node
|
62
|
-
comment = node.children[2]
|
63
|
-
@comments << ::Parser::Source::Comment.new(comment.location.expression)
|
64
|
-
return
|
65
|
-
end
|
66
|
-
|
67
|
-
node
|
68
|
-
end
|
69
|
-
|
70
|
-
def node?(node)
|
71
|
-
node.is_a?(::Parser::AST::Node)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
end
|