platformos-check 0.4.9 → 0.4.10
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +18 -18
- data/config/default.yml +9 -0
- data/docs/checks/translation_files_match.md +70 -0
- data/docs/checks/translation_key_exists.md +44 -0
- data/docs/platformos-check.jpg +0 -0
- data/lib/platformos_check/app.rb +13 -0
- data/lib/platformos_check/app_file.rb +10 -3
- data/lib/platformos_check/checks/translation_files_match.rb +83 -0
- data/lib/platformos_check/checks/translation_key_exists.rb +48 -0
- data/lib/platformos_check/checks/undefined_object.rb +1 -1
- data/lib/platformos_check/ext/hash.rb +19 -0
- data/lib/platformos_check/language_server/constants.rb +18 -2
- data/lib/platformos_check/language_server/document_link_provider.rb +67 -10
- data/lib/platformos_check/language_server/document_link_providers/localize_document_link_provider.rb +38 -0
- data/lib/platformos_check/language_server/document_link_providers/theme_render_document_link_provider.rb +2 -1
- data/lib/platformos_check/language_server/document_link_providers/translation_document_link_provider.rb +36 -0
- data/lib/platformos_check/translation_file.rb +40 -0
- data/lib/platformos_check/version.rb +1 -1
- data/lib/platformos_check/yaml_file.rb +7 -2
- data/lib/platformos_check.rb +1 -0
- metadata +11 -4
- data/docs/preview.png +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 269921738309c4cc1a1d7afef16318af6a75f050fad261530d008f53c464ce62
|
4
|
+
data.tar.gz: 0a3c1b2704f40a8244a4608ff6d9f26b0cb7757f7e93182e875edb55344c6fd9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6de2d63705409c6b3d818f48799c5c65809c26304b64d675248c21a170562098af119d954c4d5ea77f0a09559c571e64ea10a8f3417fd406c7644999048e8916
|
7
|
+
data.tar.gz: bc35549e8dc86f7f924937a9abc7306dfb6629c05311e38b092219432b9984a855b5d1bbeda8e23503cbe903fbebeff2fb4e4538a012ec4a0dd2697a8bc6f183
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,9 @@
|
|
1
|
+
v0.4.10 / 2024-02-19
|
2
|
+
==================
|
3
|
+
|
4
|
+
* Add documentLink for translations (both for `| t` and `| l` filters)
|
5
|
+
* Add TranslationKeyExists, TranslationFilesMatch offenses to warn about issues with missing translation or inconsistency between multiple language translation files
|
6
|
+
|
1
7
|
v0.4.9 / 2024-01-10
|
2
8
|
==================
|
3
9
|
|
data/README.md
CHANGED
@@ -8,28 +8,28 @@ PlatformOS Check is a tool that helps you follow platformOS recommendations & be
|
|
8
8
|
|
9
9
|
PlatformOS Check currently checks for the following:
|
10
10
|
|
11
|
-
✅ Liquid syntax errors
|
12
|
-
✅ JSON syntax errors
|
13
|
-
✅ Missing partials and graphqls
|
14
|
-
✅ Unused variables (via `{% assign var = ... %}`, {% function var = ... %} etc.)
|
15
|
-
✅ Unused partials
|
16
|
-
✅ Template length
|
17
|
-
✅ Deprecated tags
|
18
|
-
✅ Unknown tags
|
19
|
-
✅ Unknown filters
|
20
|
-
✅ Missing or extra spaces inside `{% ... %}` and `{{ ... }}`
|
21
|
-
✅ Using several `{% ... %}` instead of `{% liquid ... %}`
|
22
|
-
✅ Undefined objects
|
23
|
-
✅ Deprecated filters
|
24
|
-
✅ Missing `platformos-check-enable` comment
|
25
|
-
✅ Invalid arguments provided to `{% graphql %}` tags
|
26
|
-
✅ Missing `authenticity_token` in `<form>`
|
11
|
+
✅ Liquid syntax errors
|
12
|
+
✅ JSON syntax errors
|
13
|
+
✅ Missing partials and graphqls
|
14
|
+
✅ Unused variables (via `{% assign var = ... %}`, {% function var = ... %} etc.)
|
15
|
+
✅ Unused partials
|
16
|
+
✅ Template length
|
17
|
+
✅ Deprecated tags
|
18
|
+
✅ Unknown tags
|
19
|
+
✅ Unknown filters
|
20
|
+
✅ Missing or extra spaces inside `{% ... %}` and `{{ ... }}`
|
21
|
+
✅ Using several `{% ... %}` instead of `{% liquid ... %}`
|
22
|
+
✅ Undefined objects
|
23
|
+
✅ Deprecated filters
|
24
|
+
✅ Missing `platformos-check-enable` comment
|
25
|
+
✅ Invalid arguments provided to `{% graphql %}` tags
|
26
|
+
✅ Missing `authenticity_token` in `<form>`
|
27
27
|
✅ Unreachable code
|
28
28
|
|
29
29
|
As well as checks that prevent easy to spot performance problems:
|
30
30
|
|
31
|
-
✅ [GraphQL in for loop](/docs/checks/graphql_in_for_loop.md)
|
32
|
-
✅ Use of [parser-blocking](/docs/checks/parser_blocking_javascript.md) JavaScript
|
31
|
+
✅ [GraphQL in for loop](/docs/checks/graphql_in_for_loop.md)
|
32
|
+
✅ Use of [parser-blocking](/docs/checks/parser_blocking_javascript.md) JavaScript
|
33
33
|
✅ [Missing width and height attributes on `img` tags](/docs/checks/img_width_and_height.md)
|
34
34
|
|
35
35
|
For detailed descriptions and configuration options, [take a look at the complete list.](/docs/checks/)
|
data/config/default.yml
CHANGED
@@ -110,7 +110,16 @@ HtmlParsingError:
|
|
110
110
|
enabled: true
|
111
111
|
ignore: []
|
112
112
|
|
113
|
+
TranslationKeyExists:
|
114
|
+
enabled: true
|
115
|
+
ignore: []
|
116
|
+
|
117
|
+
TranslationFilesMatch:
|
118
|
+
enabled: true
|
119
|
+
ignore: []
|
120
|
+
|
113
121
|
ParseJsonFormat:
|
114
122
|
enabled: false
|
115
123
|
start_level: 0
|
116
124
|
indent: ' '
|
125
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
# Translation Files Match (`TranslationFilesMatch`)
|
2
|
+
|
3
|
+
Checks if translation files for different language have the same keys.
|
4
|
+
|
5
|
+
## Check Details
|
6
|
+
|
7
|
+
This check is aimed at avoiding inconsistences between translation files to avoid errors hard to spot and make maintenance easier.
|
8
|
+
|
9
|
+
:-1: Examples of **incorrect** code for this check:
|
10
|
+
|
11
|
+
```yaml
|
12
|
+
# app/translations/en/item.yml
|
13
|
+
en:
|
14
|
+
app:
|
15
|
+
item:
|
16
|
+
title: "Item"
|
17
|
+
description: "Description"
|
18
|
+
|
19
|
+
# app/translations/de/item.yml
|
20
|
+
en:
|
21
|
+
app:
|
22
|
+
item:
|
23
|
+
description: "Beschreibung"
|
24
|
+
```
|
25
|
+
|
26
|
+
Missing "title" in de/item.yml
|
27
|
+
|
28
|
+
:+1: Examples of **correct** code for this check:
|
29
|
+
|
30
|
+
```yaml
|
31
|
+
# app/translations/en/item.yml
|
32
|
+
en:
|
33
|
+
app:
|
34
|
+
item:
|
35
|
+
title: "Item"
|
36
|
+
description: "Description"
|
37
|
+
|
38
|
+
# app/translations/de/item.yml
|
39
|
+
en:
|
40
|
+
app:
|
41
|
+
item:
|
42
|
+
title: "Artikel"
|
43
|
+
description: "Beschreibung"
|
44
|
+
```
|
45
|
+
|
46
|
+
## Check Options
|
47
|
+
|
48
|
+
The default configuration for this check is the following:
|
49
|
+
|
50
|
+
```yaml
|
51
|
+
TranslationFilesMatch:
|
52
|
+
enabled: true
|
53
|
+
```
|
54
|
+
|
55
|
+
## When Not To Use It
|
56
|
+
|
57
|
+
There should be no cases where disabling this rule is needed. For keys that are set via UI, and hence should not be part of the codebase,
|
58
|
+
use proper configuration option in [app/config.yml](https://documentation.platformos.com/developer-guide/platformos-workflow/codebase/config)
|
59
|
+
|
60
|
+
## Version
|
61
|
+
|
62
|
+
This check has been introduced in PlatformOS Check 0.4.10.
|
63
|
+
|
64
|
+
## Resources
|
65
|
+
|
66
|
+
- [Rule Source][codesource]
|
67
|
+
- [Documentation Source][docsource]
|
68
|
+
|
69
|
+
[codesource]: /lib/platformos_check/checks/translation_files_match.rb
|
70
|
+
[docsource]: /docs/checks/translation_files_match.md
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Translation Key Exists (`TranslationKeyExists`)
|
2
|
+
|
3
|
+
Checks if translation key is defined in the default language
|
4
|
+
|
5
|
+
## Check Details
|
6
|
+
|
7
|
+
This check is aimed at avoiding missing translation error.
|
8
|
+
|
9
|
+
:-1: Examples of **incorrect** code for this check:
|
10
|
+
|
11
|
+
```liquid
|
12
|
+
{{ 'undefined.key' | t }}
|
13
|
+
```
|
14
|
+
|
15
|
+
:+1: Examples of **correct** code for this check:
|
16
|
+
|
17
|
+
```liquid
|
18
|
+
{{ 'defined.key' | t }}
|
19
|
+
|
20
|
+
## Check Options
|
21
|
+
|
22
|
+
The default configuration for this check is the following:
|
23
|
+
|
24
|
+
```yaml
|
25
|
+
TranslationKeyExists:
|
26
|
+
enabled: true
|
27
|
+
```
|
28
|
+
|
29
|
+
## When Not To Use It
|
30
|
+
|
31
|
+
There should be no cases where disabling this rule is needed. For keys that are set via UI, and hence should not be part of the codebase,
|
32
|
+
use proper configuration option in [app/config.yml](https://documentation.platformos.com/developer-guide/platformos-workflow/codebase/config)
|
33
|
+
|
34
|
+
## Version
|
35
|
+
|
36
|
+
This check has been introduced in PlatformOS Check 0.4.10.
|
37
|
+
|
38
|
+
## Resources
|
39
|
+
|
40
|
+
- [Rule Source][codesource]
|
41
|
+
- [Documentation Source][docsource]
|
42
|
+
|
43
|
+
[codesource]: /lib/platformos_check/checks/translation_key_exists.rb
|
44
|
+
[docsource]: /docs/checks/translation_key_exists.md
|
Binary file
|
data/lib/platformos_check/app.rb
CHANGED
@@ -39,6 +39,8 @@ module PlatformosCheck
|
|
39
39
|
CONFIG_REGEX => ConfigFile
|
40
40
|
}
|
41
41
|
|
42
|
+
DEFAULT_LANGUAGE = 'en'
|
43
|
+
|
42
44
|
attr_reader :storage, :grouped_files
|
43
45
|
|
44
46
|
def initialize(storage)
|
@@ -139,5 +141,16 @@ module PlatformosCheck
|
|
139
141
|
all.find { |t| t.relative_path.to_s == name_or_relative_path }
|
140
142
|
end
|
141
143
|
end
|
144
|
+
|
145
|
+
def default_language
|
146
|
+
DEFAULT_LANGUAGE
|
147
|
+
end
|
148
|
+
|
149
|
+
def translations_hash
|
150
|
+
@translations_hash ||= translations.each_with_object({}) do |translation_file, hash|
|
151
|
+
hash.deep_merge!(translation_file.content)
|
152
|
+
hash
|
153
|
+
end
|
154
|
+
end
|
142
155
|
end
|
143
156
|
end
|
@@ -34,16 +34,19 @@ module PlatformosCheck
|
|
34
34
|
n = remove_extension(relative_path.sub(dir_prefix, '')).to_s
|
35
35
|
return n if module_name.nil?
|
36
36
|
|
37
|
-
|
38
|
-
return n if n.start_with?(prefix)
|
37
|
+
return n if n.start_with?(module_prefix)
|
39
38
|
|
40
|
-
"#{
|
39
|
+
"#{module_prefix}#{n}"
|
41
40
|
end
|
42
41
|
|
43
42
|
def dir_prefix
|
44
43
|
nil
|
45
44
|
end
|
46
45
|
|
46
|
+
def module_prefix
|
47
|
+
@module_prefix ||= "modules#{File::SEPARATOR}#{module_name}#{File::SEPARATOR}"
|
48
|
+
end
|
49
|
+
|
47
50
|
def module_name
|
48
51
|
@module_name ||= begin
|
49
52
|
dir_names = @relative_path.split(File::SEPARATOR).reject(&:empty?)
|
@@ -85,6 +88,10 @@ module PlatformosCheck
|
|
85
88
|
false
|
86
89
|
end
|
87
90
|
|
91
|
+
def translation?
|
92
|
+
false
|
93
|
+
end
|
94
|
+
|
88
95
|
def ==(other)
|
89
96
|
other.is_a?(self.class) && relative_path == other.relative_path
|
90
97
|
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PlatformosCheck
|
4
|
+
class TranslationFilesMatch < YamlCheck
|
5
|
+
severity :error
|
6
|
+
category :translation
|
7
|
+
doc docs_url(__FILE__)
|
8
|
+
|
9
|
+
PLURALIZATION_KEYS = Set.new(%w[zero one two few many other])
|
10
|
+
|
11
|
+
def on_file(file)
|
12
|
+
return unless file.translation?
|
13
|
+
return if file.parse_error
|
14
|
+
return add_offense_wrong_language_in_file(file) if file.language != file.language_from_path
|
15
|
+
return check_if_file_exists_for_all_other_languages(file) if file.language == @platformos_app.default_language
|
16
|
+
|
17
|
+
default_language_file = @platformos_app.grouped_files[PlatformosCheck::TranslationFile][file.name.sub(file.language, @platformos_app.default_language)]
|
18
|
+
|
19
|
+
return add_offense_missing_file(file) if default_language_file.nil?
|
20
|
+
|
21
|
+
add_offense_different_structure(file, default_language_file) unless same_structure?(default_language_file.content[@platformos_app.default_language], file.content[file.language])
|
22
|
+
end
|
23
|
+
|
24
|
+
protected
|
25
|
+
|
26
|
+
def add_offense_wrong_language_in_file(file)
|
27
|
+
add_offense("Mismatch detected - file inside #{file.language_from_path} directory defines translations for `#{file.language}`", app_file: file) do |_corrector|
|
28
|
+
file.update_contents(file.content[file.language_from_path] = file.content.delete(file.content[file.language]))
|
29
|
+
file.write
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def add_offense_missing_file(file)
|
34
|
+
add_offense("Mismatch detected - missing `#{file.relative_path.to_s.sub(file.language, @platformos_app.default_language)}` to define translations the default language", app_file: file)
|
35
|
+
end
|
36
|
+
|
37
|
+
def check_if_file_exists_for_all_other_languages(file)
|
38
|
+
@platformos_app.translations_hash.each_key do |lang|
|
39
|
+
next if lang == @platformos_app.default_language
|
40
|
+
|
41
|
+
language_file = @platformos_app.grouped_files[PlatformosCheck::TranslationFile][file.name.sub(file.language, lang)]
|
42
|
+
add_offense_missing_translation_file(file, lang) if language_file.nil?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def add_offense_missing_translation_file(file, lang)
|
47
|
+
missing_file_path = file.relative_path.to_s.sub(file.language, lang)
|
48
|
+
add_offense("Mismatch detected - missing `#{missing_file_path}` file to define translations for `#{lang}`", app_file: file) do |corrector|
|
49
|
+
missing_file_content = file.content.clone
|
50
|
+
missing_file_content[lang] = missing_file_content.delete(file.language)
|
51
|
+
corrector.create_file(@platformos_app.storage, missing_file_path, YAML.dump(missing_file_content))
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def same_structure?(hash1, hash2)
|
56
|
+
if !hash1.is_a?(Hash) && !hash2.is_a?(Hash)
|
57
|
+
true
|
58
|
+
elsif (hash1.is_a?(Hash) && !hash2.is_a?(Hash)) || (!hash1.is_a?(Hash) && hash2.is_a?(Hash))
|
59
|
+
false
|
60
|
+
elsif pluralization?(hash1) && pluralization?(hash2)
|
61
|
+
true
|
62
|
+
elsif hash1.keys.map(&:to_s).sort != hash2.keys.map(&:to_s).sort
|
63
|
+
false
|
64
|
+
else
|
65
|
+
hash1.keys.all? { |key| same_structure?(hash1[key], hash2[key]) }
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def add_offense_different_structure(file, default_language_file)
|
70
|
+
add_offense("Mismatch detected - structure differs from the default language file #{default_language_file.relative_path}", app_file: file) do |_corrector|
|
71
|
+
file.content[file.language].transform_values! { |v| v.nil? ? {} : v }
|
72
|
+
file.content[file.language] = default_language_file.content[default_language_file.language].deep_merge(file.content[file.language])
|
73
|
+
file.write
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def pluralization?(hash)
|
78
|
+
hash.all? do |key, value|
|
79
|
+
PLURALIZATION_KEYS.include?(key) && !value.is_a?(Hash)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PlatformosCheck
|
4
|
+
# Recommends using {% liquid ... %} if 5 or more consecutive {% ... %} are found.
|
5
|
+
class TranslationKeyExists < LiquidCheck
|
6
|
+
severity :error
|
7
|
+
categories :translation, :liquid
|
8
|
+
doc docs_url(__FILE__)
|
9
|
+
|
10
|
+
def on_variable(node)
|
11
|
+
return unless node.value.name.is_a?(String)
|
12
|
+
return unless node.filters.size == 1
|
13
|
+
|
14
|
+
translation_filter = node.filters.detect { |f| TranslationFile::TRANSLATION_FILTERS.include?(f[0]) }
|
15
|
+
return unless translation_filter
|
16
|
+
return unless translation_filter
|
17
|
+
|
18
|
+
filter_attributes = translation_filter[2] || {}
|
19
|
+
|
20
|
+
return unless filter_attributes['default'].nil?
|
21
|
+
return if !filter_attributes['scope'].nil? && !filter_attributes['scope'].is_a?(String)
|
22
|
+
|
23
|
+
lang = filter_attributes['language'].is_a?(String) ? filter_attributes['language'] : @platformos_app.default_language
|
24
|
+
translation_components = node.value.name.split('.')
|
25
|
+
|
26
|
+
translation_components = filter_attributes['scope'].split('.') + translation_components if filter_attributes['scope']
|
27
|
+
|
28
|
+
return add_translation_offense(node:, lang:) if @platformos_app.translations_hash.empty?
|
29
|
+
|
30
|
+
hash = @platformos_app.translations_hash[lang] || {}
|
31
|
+
index = 0
|
32
|
+
while translation_components[index]
|
33
|
+
hash = hash[translation_components[index]]
|
34
|
+
if hash.nil?
|
35
|
+
add_translation_offense(node:, lang:)
|
36
|
+
break
|
37
|
+
end
|
38
|
+
index += 1
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def add_translation_offense(node:, lang:)
|
45
|
+
add_offense("Translation `#{lang}.#{node.value.name}` does not exists", node:)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
def deep_merge!(other_hash, &block)
|
5
|
+
merge!(other_hash) do |key, this_val, other_val|
|
6
|
+
if this_val.is_a?(Hash) && other_val.is_a?(Hash)
|
7
|
+
this_val.deep_merge(other_val, &block)
|
8
|
+
elsif block
|
9
|
+
yield(key, this_val, other_val)
|
10
|
+
else
|
11
|
+
other_val
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def deep_merge(other_hash, &)
|
17
|
+
dup.deep_merge!(other_hash, &)
|
18
|
+
end
|
19
|
+
end
|
@@ -32,13 +32,29 @@ module PlatformosCheck
|
|
32
32
|
PARTIAL_GRAPHQL = partial_tag_with_result('graphql')
|
33
33
|
PARTIAL_BACKGROUND = partial_tag_with_result('background')
|
34
34
|
|
35
|
+
TAGS_FOR_FILTERS = 'echo|print|log|hash_assign|assign'
|
36
|
+
TRANSLATION_FILTERS_NAMES = 'translate|t_escape|translate_escape|t[^\\w]'
|
37
|
+
OPTIONAL_SCOPE_ARGUMENT = %((:?([\\w:'"\\s]*)\\s*(scope:\\s*['"](?<scope>[^'"]*)['"]))?)
|
38
|
+
|
39
|
+
LOCALIZE_FILTERS_NAMES = ''
|
40
|
+
|
35
41
|
ASSET_INCLUDE = /
|
36
42
|
\{\{-?\s*'(?<partial>[^']*)'\s*\|\s*asset_url|
|
37
43
|
\{\{-?\s*"(?<partial>[^"]*)"\s*\|\s*asset_url|
|
38
44
|
|
39
45
|
# in liquid tags the whole line is white space until the asset partial
|
40
|
-
^\s*(
|
41
|
-
^\s*(
|
46
|
+
^\s*(?:#{TAGS_FOR_FILTERS}[^=]*=)\s*'(?<partial>[^']*)'\s*\|\s*asset_url|
|
47
|
+
^\s*(?:#{TAGS_FOR_FILTERS}[^=]*=)\s*"(?<partial>[^"]*)"\s*\|\s*asset_url
|
48
|
+
/mix
|
49
|
+
|
50
|
+
TRANSLATION_FILTER = /
|
51
|
+
'(?<key>[^']*)'\s*\|\s*(#{TRANSLATION_FILTERS_NAMES})#{OPTIONAL_SCOPE_ARGUMENT}|
|
52
|
+
"(?<key>[^"]*)"\s*\|\s*(#{TRANSLATION_FILTERS_NAMES})#{OPTIONAL_SCOPE_ARGUMENT}
|
53
|
+
/mix
|
54
|
+
|
55
|
+
LOCALIZE_FILTER = /
|
56
|
+
[\s\w'"-:.]+\|\s*(localize|l):\s*'(?<key>[^']*)'|
|
57
|
+
[\s\w'"-:.]+\|\s*(localize|l):\s*"(?<key>[^"]*)"
|
42
58
|
/mix
|
43
59
|
end
|
44
60
|
end
|
@@ -7,6 +7,16 @@ module PlatformosCheck
|
|
7
7
|
include PositionHelper
|
8
8
|
include URIHelper
|
9
9
|
|
10
|
+
class DefaultTranslationFile
|
11
|
+
def initialize(default_language)
|
12
|
+
@default_language = default_language
|
13
|
+
end
|
14
|
+
|
15
|
+
def relative_path
|
16
|
+
Pathname.new(@default_language, "#{@default_language}.yml")
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
10
20
|
class << self
|
11
21
|
attr_accessor :partial_regexp, :app_file_type, :default_dir, :default_extension
|
12
22
|
|
@@ -41,18 +51,12 @@ module PlatformosCheck
|
|
41
51
|
|
42
52
|
def document_links(buffer, platformos_app)
|
43
53
|
matches(buffer, partial_regexp).map do |match|
|
44
|
-
start_row, start_column =
|
45
|
-
buffer,
|
46
|
-
match.begin(:partial)
|
47
|
-
)
|
54
|
+
start_row, start_column = start_coordinates(buffer, match)
|
48
55
|
|
49
|
-
end_row, end_column =
|
50
|
-
buffer,
|
51
|
-
match.end(:partial)
|
52
|
-
)
|
56
|
+
end_row, end_column = end_coordinates(buffer, match)
|
53
57
|
|
54
58
|
{
|
55
|
-
target: file_link(match
|
59
|
+
target: file_link(match, platformos_app),
|
56
60
|
range: {
|
57
61
|
start: {
|
58
62
|
line: start_row,
|
@@ -67,13 +71,66 @@ module PlatformosCheck
|
|
67
71
|
end
|
68
72
|
end
|
69
73
|
|
70
|
-
def
|
74
|
+
def start_coordinates(buffer, match)
|
75
|
+
from_index_to_row_column(
|
76
|
+
buffer,
|
77
|
+
match.begin(:partial)
|
78
|
+
)
|
79
|
+
end
|
80
|
+
|
81
|
+
def end_coordinates(buffer, match)
|
82
|
+
from_index_to_row_column(
|
83
|
+
buffer,
|
84
|
+
match.end(:partial)
|
85
|
+
)
|
86
|
+
end
|
87
|
+
|
88
|
+
def file_link(match, platformos_app)
|
89
|
+
partial = match[:partial]
|
71
90
|
relative_path = platformos_app.send(app_file_type).detect { |f| f.name == partial }&.relative_path
|
72
91
|
relative_path ||= default_relative_path(partial)
|
73
92
|
|
74
93
|
file_uri(@storage.path(relative_path))
|
75
94
|
end
|
76
95
|
|
96
|
+
def translation_file_link(match, platformos_app)
|
97
|
+
@current_best_fit = platformos_app.translations.first || DefaultTranslationFile.new(platformos_app.default_language)
|
98
|
+
@current_best_fit_level = 0
|
99
|
+
array_of_translation_components = translation_components_for_match(match)
|
100
|
+
platformos_app.translations.each do |translation_file|
|
101
|
+
array_of_translation_components.each do |translation_components|
|
102
|
+
exact_match_level = translation_components.size
|
103
|
+
component_result = translation_file.content[platformos_app.default_language]
|
104
|
+
next if component_result.nil?
|
105
|
+
|
106
|
+
i = 0
|
107
|
+
while i < exact_match_level
|
108
|
+
component_result = yaml(component_result, translation_components[i])
|
109
|
+
|
110
|
+
break if component_result.nil?
|
111
|
+
|
112
|
+
i += 1
|
113
|
+
if i > @current_best_fit_level
|
114
|
+
@current_best_fit = translation_file
|
115
|
+
@current_best_fit_level = i
|
116
|
+
end
|
117
|
+
|
118
|
+
break unless component_result.is_a?(Hash)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
file_uri(@storage.path(@current_best_fit&.relative_path))
|
124
|
+
end
|
125
|
+
|
126
|
+
def translation_components_for_match(match)
|
127
|
+
raise NotImplementedError
|
128
|
+
end
|
129
|
+
|
130
|
+
def yaml(component_result, component)
|
131
|
+
component_result[component]
|
132
|
+
end
|
133
|
+
|
77
134
|
def default_relative_path(partial)
|
78
135
|
return Pathname.new("app/#{default_dir}/#{partial}#{default_extension}") unless partial.start_with?('modules/')
|
79
136
|
|
data/lib/platformos_check/language_server/document_link_providers/localize_document_link_provider.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PlatformosCheck
|
4
|
+
module LanguageServer
|
5
|
+
class LocalizeDocumentLinkProvider < DocumentLinkProvider
|
6
|
+
@partial_regexp = LOCALIZE_FILTER
|
7
|
+
@app_file_type = :translations
|
8
|
+
@default_dir = 'translations'
|
9
|
+
@default_extension = '.yml'
|
10
|
+
|
11
|
+
def file_link(match, platformos_app)
|
12
|
+
translation_file_link(match, platformos_app)
|
13
|
+
end
|
14
|
+
|
15
|
+
def translation_components_for_match(match)
|
16
|
+
key = match[:key].split('.')
|
17
|
+
[
|
18
|
+
%w[time formats] + key,
|
19
|
+
%w[date formats] + key
|
20
|
+
]
|
21
|
+
end
|
22
|
+
|
23
|
+
def start_coordinates(buffer, match)
|
24
|
+
from_index_to_row_column(
|
25
|
+
buffer,
|
26
|
+
match.begin(:key)
|
27
|
+
)
|
28
|
+
end
|
29
|
+
|
30
|
+
def end_coordinates(buffer, match)
|
31
|
+
from_index_to_row_column(
|
32
|
+
buffer,
|
33
|
+
match.end(:key)
|
34
|
+
)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -8,7 +8,8 @@ module PlatformosCheck
|
|
8
8
|
@default_dir = 'views/partials'
|
9
9
|
@default_extension = '.liquid'
|
10
10
|
|
11
|
-
def file_link(
|
11
|
+
def file_link(match, platformos_app)
|
12
|
+
partial = match[:partial]
|
12
13
|
relative_path = nil
|
13
14
|
path_prefixes(platformos_app).each do |prefix|
|
14
15
|
prefix ||= ''
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PlatformosCheck
|
4
|
+
module LanguageServer
|
5
|
+
class TranslationDocumentLinkProvider < DocumentLinkProvider
|
6
|
+
@partial_regexp = TRANSLATION_FILTER
|
7
|
+
@app_file_type = :translations
|
8
|
+
@default_dir = 'translations'
|
9
|
+
@default_extension = '.yml'
|
10
|
+
|
11
|
+
def file_link(match, platformos_app)
|
12
|
+
translation_file_link(match, platformos_app)
|
13
|
+
end
|
14
|
+
|
15
|
+
def translation_components_for_match(match)
|
16
|
+
translation_components = match[:key].split('.')
|
17
|
+
translation_components = match[:scope].split('.') + translation_components if match[:scope]
|
18
|
+
[translation_components]
|
19
|
+
end
|
20
|
+
|
21
|
+
def start_coordinates(buffer, match)
|
22
|
+
from_index_to_row_column(
|
23
|
+
buffer,
|
24
|
+
match.begin(:key)
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
def end_coordinates(buffer, match)
|
29
|
+
from_index_to_row_column(
|
30
|
+
buffer,
|
31
|
+
match.end(:key)
|
32
|
+
)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -2,5 +2,45 @@
|
|
2
2
|
|
3
3
|
module PlatformosCheck
|
4
4
|
class TranslationFile < YamlFile
|
5
|
+
DIR_PREFIX = %r{\A/?((marketplace_builder|app)/(translations)/|modules/((\w|-)*)/(private|public)/(translations)/)}
|
6
|
+
TRANSLATION_FILTERS = Set.new(%w[t t_escape translate translate_escape]).freeze
|
7
|
+
attr_reader :language
|
8
|
+
|
9
|
+
def load!
|
10
|
+
before_load
|
11
|
+
super
|
12
|
+
after_load
|
13
|
+
end
|
14
|
+
|
15
|
+
def before_load
|
16
|
+
@storage.platformos_app.instance_variable_set(:@translations_hash, nil) unless @loaded
|
17
|
+
end
|
18
|
+
|
19
|
+
def after_load
|
20
|
+
@language = @content&.keys&.first
|
21
|
+
return if module_name.nil?
|
22
|
+
|
23
|
+
@content[@language].transform_keys! { |key| key.start_with?(module_prefix) ? key : "#{module_prefix}#{key}" }
|
24
|
+
end
|
25
|
+
|
26
|
+
def language_from_path
|
27
|
+
@language_from_path ||= name.sub(module_prefix, '').split(File::SEPARATOR).first
|
28
|
+
end
|
29
|
+
|
30
|
+
def update_contents(new_content = {})
|
31
|
+
before_load
|
32
|
+
super(new_content)
|
33
|
+
@loaded = true
|
34
|
+
|
35
|
+
after_load
|
36
|
+
end
|
37
|
+
|
38
|
+
def dir_prefix
|
39
|
+
DIR_PREFIX
|
40
|
+
end
|
41
|
+
|
42
|
+
def translation?
|
43
|
+
true
|
44
|
+
end
|
5
45
|
end
|
6
46
|
end
|
@@ -28,14 +28,19 @@ module PlatformosCheck
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def write
|
31
|
+
pretty = content_to_string
|
32
|
+
@storage.write(@relative_path, pretty)
|
33
|
+
@source = pretty
|
34
|
+
end
|
35
|
+
|
36
|
+
def content_to_string
|
31
37
|
pretty = YAML.dump(@content)
|
32
38
|
return unless source.rstrip != pretty.rstrip
|
33
39
|
|
34
40
|
# Most editors add a trailing \n at the end of files. Here we
|
35
41
|
# try to maintain the convention.
|
36
42
|
eof = source.end_with?("\n") ? "\n" : ""
|
37
|
-
|
38
|
-
@source = pretty
|
43
|
+
pretty.gsub("\n", @eol) + eof
|
39
44
|
end
|
40
45
|
|
41
46
|
def yaml?
|
data/lib/platformos_check.rb
CHANGED
@@ -5,6 +5,7 @@ require "liquid"
|
|
5
5
|
require_relative "platformos_check/version"
|
6
6
|
require_relative "platformos_check/bug"
|
7
7
|
require_relative "platformos_check/exceptions"
|
8
|
+
require_relative "platformos_check/ext/hash"
|
8
9
|
require_relative "platformos_check/json_helper"
|
9
10
|
require_relative "platformos_check/app_file_rewriter"
|
10
11
|
require_relative "platformos_check/app_file"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: platformos-check
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Piotr Bliszczyk
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2024-
|
13
|
+
date: 2024-02-19 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: graphql
|
@@ -134,6 +134,8 @@ files:
|
|
134
134
|
- docs/checks/space_inside_braces.md
|
135
135
|
- docs/checks/syntax_error.md
|
136
136
|
- docs/checks/template_length.md
|
137
|
+
- docs/checks/translation_files_match.md
|
138
|
+
- docs/checks/translation_key_exists.md
|
137
139
|
- docs/checks/undefined_object.md
|
138
140
|
- docs/checks/unknown_filter.md
|
139
141
|
- docs/checks/unreachable_code.md
|
@@ -148,7 +150,7 @@ files:
|
|
148
150
|
- docs/language_server/code-action-problem.png
|
149
151
|
- docs/language_server/code-action-quickfix.png
|
150
152
|
- docs/language_server/how_to_correct_code_with_code_actions_and_execute_command.md
|
151
|
-
- docs/
|
153
|
+
- docs/platformos-check.jpg
|
152
154
|
- exe/platformos-check
|
153
155
|
- exe/platformos-check-language-server
|
154
156
|
- lib/platformos_check.rb
|
@@ -181,6 +183,8 @@ files:
|
|
181
183
|
- lib/platformos_check/checks/space_inside_braces.rb
|
182
184
|
- lib/platformos_check/checks/syntax_error.rb
|
183
185
|
- lib/platformos_check/checks/template_length.rb
|
186
|
+
- lib/platformos_check/checks/translation_files_match.rb
|
187
|
+
- lib/platformos_check/checks/translation_key_exists.rb
|
184
188
|
- lib/platformos_check/checks/undefined_object.rb
|
185
189
|
- lib/platformos_check/checks/unknown_filter.rb
|
186
190
|
- lib/platformos_check/checks/unreachable_code.rb
|
@@ -196,6 +200,7 @@ files:
|
|
196
200
|
- lib/platformos_check/disabled_checks.rb
|
197
201
|
- lib/platformos_check/email_file.rb
|
198
202
|
- lib/platformos_check/exceptions.rb
|
203
|
+
- lib/platformos_check/ext/hash.rb
|
199
204
|
- lib/platformos_check/file_system_storage.rb
|
200
205
|
- lib/platformos_check/form_file.rb
|
201
206
|
- lib/platformos_check/graphql_file.rb
|
@@ -244,8 +249,10 @@ files:
|
|
244
249
|
- lib/platformos_check/language_server/document_link_providers/graphql_document_link_provider.rb
|
245
250
|
- lib/platformos_check/language_server/document_link_providers/include_document_link_provider.rb
|
246
251
|
- lib/platformos_check/language_server/document_link_providers/include_form_document_link_provider.rb
|
252
|
+
- lib/platformos_check/language_server/document_link_providers/localize_document_link_provider.rb
|
247
253
|
- lib/platformos_check/language_server/document_link_providers/render_document_link_provider.rb
|
248
254
|
- lib/platformos_check/language_server/document_link_providers/theme_render_document_link_provider.rb
|
255
|
+
- lib/platformos_check/language_server/document_link_providers/translation_document_link_provider.rb
|
249
256
|
- lib/platformos_check/language_server/execute_command_engine.rb
|
250
257
|
- lib/platformos_check/language_server/execute_command_provider.rb
|
251
258
|
- lib/platformos_check/language_server/execute_command_providers/correction_execute_command_provider.rb
|
@@ -366,7 +373,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
366
373
|
- !ruby/object:Gem::Version
|
367
374
|
version: '0'
|
368
375
|
requirements: []
|
369
|
-
rubygems_version: 3.
|
376
|
+
rubygems_version: 3.5.6
|
370
377
|
signing_key:
|
371
378
|
specification_version: 4
|
372
379
|
summary: A platformOS App Linter
|
data/docs/preview.png
DELETED
Binary file
|