moz-fluent-linter 0.4.7__tar.gz → 0.4.8__tar.gz
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.
- {moz_fluent_linter-0.4.7/src/moz_fluent_linter.egg-info → moz_fluent_linter-0.4.8}/PKG-INFO +4 -3
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/README.md +1 -1
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/setup.cfg +1 -1
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/setup.py +1 -0
- moz_fluent_linter-0.4.8/src/fluent_linter/__init__.py +1 -0
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/fluent_linter/linter.py +57 -39
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8/src/moz_fluent_linter.egg-info}/PKG-INFO +4 -3
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_banned_words.py +6 -4
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_brands.py +6 -5
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_comments.py +6 -4
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_comments_variables.py +6 -4
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_ids.py +6 -4
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_placeable_style.py +6 -4
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/tests/test_syntax.py +6 -4
- moz_fluent_linter-0.4.8/tests/test_typography.py +222 -0
- moz_fluent_linter-0.4.7/src/fluent_linter/__init__.py +0 -1
- moz_fluent_linter-0.4.7/tests/test_typography.py +0 -112
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/LICENSE +0 -0
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/pyproject.toml +0 -0
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/SOURCES.txt +0 -0
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/dependency_links.txt +0 -0
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/entry_points.txt +0 -0
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/requires.txt +0 -0
- {moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: moz-fluent-linter
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.8
|
4
4
|
Summary: Linter package used to check Fluent files
|
5
5
|
Home-page: https://github.com/mozilla-l10n/moz-fluent-linter
|
6
6
|
Author: Francesco Lodolo
|
@@ -18,6 +18,7 @@ License-File: LICENSE
|
|
18
18
|
Requires-Dist: fluent.syntax~=0.19.0
|
19
19
|
Requires-Dist: pyyaml
|
20
20
|
Requires-Dist: six
|
21
|
+
Dynamic: license-file
|
21
22
|
|
22
23
|
# Fluent Linter
|
23
24
|
|
@@ -41,7 +42,7 @@ Using [pre-commit](https://pre-commit.com/), add this to the `.pre-commit-config
|
|
41
42
|
```yaml
|
42
43
|
repos:
|
43
44
|
- repo: https://github.com/mozilla-l10n/moz-fluent-linter
|
44
|
-
rev: v0.4.
|
45
|
+
rev: v0.4.8
|
45
46
|
hooks:
|
46
47
|
- id: fluent_linter
|
47
48
|
files: \.ftl$
|
@@ -0,0 +1 @@
|
|
1
|
+
version = "0.4.8"
|
@@ -5,15 +5,19 @@
|
|
5
5
|
# This script is largely based on the Fluent Linter used in mozilla-central
|
6
6
|
# https://firefox-source-docs.mozilla.org/code-quality/lint/linters/fluent-lint.html
|
7
7
|
|
8
|
-
from fluent.syntax import ast, parse, serializer, visitor
|
9
|
-
from html.parser import HTMLParser
|
10
8
|
import argparse
|
11
9
|
import bisect
|
12
10
|
import os
|
13
11
|
import re
|
14
12
|
import sys
|
13
|
+
|
14
|
+
from html.parser import HTMLParser
|
15
|
+
|
15
16
|
import yaml
|
16
17
|
|
18
|
+
from fluent.syntax import ast, parse, serializer, visitor
|
19
|
+
|
20
|
+
|
17
21
|
try:
|
18
22
|
from fluent_linter import version
|
19
23
|
except Exception:
|
@@ -160,31 +164,42 @@ class Linter(visitor.Visitor):
|
|
160
164
|
f" hard-coded brand names ({', '.join(found_brands)})",
|
161
165
|
)
|
162
166
|
|
163
|
-
if
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
167
|
+
if (
|
168
|
+
self.config.get("TE01", {}).get("enabled", True)
|
169
|
+
and self.apostrophe_re.search(cleaned_str)
|
170
|
+
and not self.exclude_message("TE01", message_id)
|
171
|
+
):
|
172
|
+
self.add_error(
|
173
|
+
node,
|
174
|
+
message_id,
|
175
|
+
"TE01",
|
176
|
+
"Strings with apostrophes should use foo\u2019s instead of foo's.",
|
177
|
+
)
|
178
|
+
if (
|
179
|
+
self.config.get("TE02", {}).get("enabled", True)
|
180
|
+
and self.incorrect_apostrophe_re.search(cleaned_str)
|
181
|
+
and not self.exclude_message("TE02", message_id)
|
182
|
+
):
|
183
|
+
self.add_error(
|
184
|
+
node,
|
185
|
+
message_id,
|
186
|
+
"TE02",
|
187
|
+
"Strings with apostrophes should use foo\u2019s instead of foo\u2018s.",
|
188
|
+
)
|
189
|
+
if (
|
190
|
+
self.config.get("TE03", {}).get("enabled", True)
|
191
|
+
and self.single_quote_re.search(cleaned_str)
|
192
|
+
and not self.exclude_message("TE03", message_id)
|
193
|
+
):
|
194
|
+
self.add_error(
|
195
|
+
node,
|
196
|
+
message_id,
|
197
|
+
"TE03",
|
198
|
+
"Single-quoted strings should use Unicode \u2018foo\u2019 instead of 'foo'.",
|
199
|
+
)
|
200
|
+
if self.config.get("TE04", {}).get(
|
201
|
+
"enabled", True
|
202
|
+
) and self.double_quote_re.search(cleaned_str):
|
188
203
|
# Ignore parameterized terms and other functions
|
189
204
|
for regex in self.ftl_syntax_re:
|
190
205
|
cleaned_str = regex.sub("", cleaned_str)
|
@@ -198,15 +213,18 @@ class Linter(visitor.Visitor):
|
|
198
213
|
"TE04",
|
199
214
|
'Double-quoted strings should use Unicode \u201cfoo\u201d instead of "foo".',
|
200
215
|
)
|
201
|
-
if
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
216
|
+
if (
|
217
|
+
self.config.get("TE05", {}).get("enabled", True)
|
218
|
+
and self.ellipsis_re.search(cleaned_str)
|
219
|
+
and not self.exclude_message("TE05", message_id)
|
220
|
+
):
|
221
|
+
self.add_error(
|
222
|
+
node,
|
223
|
+
message_id,
|
224
|
+
"TE05",
|
225
|
+
"Strings with an ellipsis should use the Unicode \u2026 character"
|
226
|
+
" instead of three periods",
|
227
|
+
)
|
210
228
|
|
211
229
|
def generic_visit(self, node):
|
212
230
|
node_name = type(node).__name__
|
@@ -418,9 +436,9 @@ class Linter(visitor.Visitor):
|
|
418
436
|
and not self.config["PS01"]["disabled"]
|
419
437
|
and type(node.expression) not in [ast.SelectExpression]
|
420
438
|
):
|
421
|
-
if
|
439
|
+
if isinstance(node.expression, ast.VariableReference):
|
422
440
|
placeable_name = f"${node.expression.id.name}"
|
423
|
-
elif
|
441
|
+
elif isinstance(node.expression, ast.TermReference):
|
424
442
|
placeable_name = f"-{node.expression.id.name}"
|
425
443
|
else:
|
426
444
|
placeable_name = node.expression.id.name
|
@@ -455,7 +473,7 @@ class Linter(visitor.Visitor):
|
|
455
473
|
# Store the variable used for the SelectExpression, excluding functions
|
456
474
|
# like PLATFORM()
|
457
475
|
if (
|
458
|
-
|
476
|
+
isinstance(node.selector, ast.VariableReference)
|
459
477
|
and node.selector.id.name not in self.state["variables"]
|
460
478
|
):
|
461
479
|
self.state["variables"].append(node.selector.id.name)
|
@@ -1,6 +1,6 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.4
|
2
2
|
Name: moz-fluent-linter
|
3
|
-
Version: 0.4.
|
3
|
+
Version: 0.4.8
|
4
4
|
Summary: Linter package used to check Fluent files
|
5
5
|
Home-page: https://github.com/mozilla-l10n/moz-fluent-linter
|
6
6
|
Author: Francesco Lodolo
|
@@ -18,6 +18,7 @@ License-File: LICENSE
|
|
18
18
|
Requires-Dist: fluent.syntax~=0.19.0
|
19
19
|
Requires-Dist: pyyaml
|
20
20
|
Requires-Dist: six
|
21
|
+
Dynamic: license-file
|
21
22
|
|
22
23
|
# Fluent Linter
|
23
24
|
|
@@ -41,7 +42,7 @@ Using [pre-commit](https://pre-commit.com/), add this to the `.pre-commit-config
|
|
41
42
|
```yaml
|
42
43
|
repos:
|
43
44
|
- repo: https://github.com/mozilla-l10n/moz-fluent-linter
|
44
|
-
rev: v0.4.
|
45
|
+
rev: v0.4.8
|
45
46
|
hooks:
|
46
47
|
- id: fluent_linter
|
47
48
|
files: \.ftl$
|
@@ -1,16 +1,18 @@
|
|
1
1
|
import unittest
|
2
|
-
|
2
|
+
|
3
3
|
from fluent.syntax import parse
|
4
4
|
|
5
|
+
from src.fluent_linter import linter
|
6
|
+
|
5
7
|
|
6
8
|
class TestBannedWords(unittest.TestCase):
|
7
9
|
def checkContent(self, config, content):
|
8
|
-
|
10
|
+
ftl_linter = linter.Linter(
|
9
11
|
"file.ftl", "root", config, content, linter.get_offsets_and_lines(content)
|
10
12
|
)
|
11
|
-
|
13
|
+
ftl_linter.visit(parse(content))
|
12
14
|
|
13
|
-
return
|
15
|
+
return ftl_linter.results
|
14
16
|
|
15
17
|
def testCO01(self):
|
16
18
|
content = """
|
@@ -1,16 +1,18 @@
|
|
1
1
|
import unittest
|
2
|
-
|
2
|
+
|
3
3
|
from fluent.syntax import parse
|
4
4
|
|
5
|
+
from src.fluent_linter import linter
|
6
|
+
|
5
7
|
|
6
8
|
class TestBrands(unittest.TestCase):
|
7
9
|
def checkContent(self, config, content):
|
8
|
-
|
10
|
+
ftl_linter = linter.Linter(
|
9
11
|
"file.ftl", "root", config, content, linter.get_offsets_and_lines(content)
|
10
12
|
)
|
11
|
-
|
13
|
+
ftl_linter.visit(parse(content))
|
12
14
|
|
13
|
-
return
|
15
|
+
return ftl_linter.results
|
14
16
|
|
15
17
|
def testCO01(self):
|
16
18
|
content = """
|
@@ -82,7 +84,6 @@ good-account2 = Set up your { -brand-short-name } Account.
|
|
82
84
|
|
83
85
|
config = {"CO01": {"enabled": True, "brands": ["Monitor"], "exclusions": {}}}
|
84
86
|
results = self.checkContent(config, content)
|
85
|
-
print("\n".join(results))
|
86
87
|
self.assertEqual(len(results), 1)
|
87
88
|
self.assertTrue("bad-monitor" in results[0])
|
88
89
|
self.assertTrue("good-monitor" not in results[0])
|
@@ -1,16 +1,18 @@
|
|
1
1
|
import unittest
|
2
|
-
|
2
|
+
|
3
3
|
from fluent.syntax import parse
|
4
4
|
|
5
|
+
from src.fluent_linter import linter
|
6
|
+
|
5
7
|
|
6
8
|
class TestComments(unittest.TestCase):
|
7
9
|
def checkContent(self, config, content):
|
8
|
-
|
10
|
+
ftl_linter = linter.Linter(
|
9
11
|
"path", "root", config, content, linter.get_offsets_and_lines(content)
|
10
12
|
)
|
11
|
-
|
13
|
+
ftl_linter.visit(parse(content))
|
12
14
|
|
13
|
-
return
|
15
|
+
return ftl_linter.results
|
14
16
|
|
15
17
|
def testGC01(self):
|
16
18
|
content = """
|
@@ -1,16 +1,18 @@
|
|
1
1
|
import unittest
|
2
|
-
|
2
|
+
|
3
3
|
from fluent.syntax import parse
|
4
4
|
|
5
|
+
from src.fluent_linter import linter
|
6
|
+
|
5
7
|
|
6
8
|
class TestCommentVariables(unittest.TestCase):
|
7
9
|
def checkContent(self, config, content):
|
8
|
-
|
10
|
+
ftl_linter = linter.Linter(
|
9
11
|
"path", "root", config, content, linter.get_offsets_and_lines(content)
|
10
12
|
)
|
11
|
-
|
13
|
+
ftl_linter.visit(parse(content))
|
12
14
|
|
13
|
-
return
|
15
|
+
return ftl_linter.results
|
14
16
|
|
15
17
|
def testVC01(self):
|
16
18
|
content = """
|
@@ -1,16 +1,18 @@
|
|
1
1
|
import unittest
|
2
|
-
|
2
|
+
|
3
3
|
from fluent.syntax import parse
|
4
4
|
|
5
|
+
from src.fluent_linter import linter
|
6
|
+
|
5
7
|
|
6
8
|
class TestIDs(unittest.TestCase):
|
7
9
|
def checkContent(self, path, root, config, content):
|
8
|
-
|
10
|
+
ftl_linter = linter.Linter(
|
9
11
|
path, root, config, content, linter.get_offsets_and_lines(content)
|
10
12
|
)
|
11
|
-
|
13
|
+
ftl_linter.visit(parse(content))
|
12
14
|
|
13
|
-
return
|
15
|
+
return ftl_linter.results
|
14
16
|
|
15
17
|
def testID01(self):
|
16
18
|
content = """
|
@@ -1,16 +1,18 @@
|
|
1
1
|
import unittest
|
2
|
-
|
2
|
+
|
3
3
|
from fluent.syntax import parse
|
4
4
|
|
5
|
+
from src.fluent_linter import linter
|
6
|
+
|
5
7
|
|
6
8
|
class TestPlaceableStyle(unittest.TestCase):
|
7
9
|
def checkContent(self, config, content):
|
8
|
-
|
10
|
+
ftl_linter = linter.Linter(
|
9
11
|
"path", "root", config, content, linter.get_offsets_and_lines(content)
|
10
12
|
)
|
11
|
-
|
13
|
+
ftl_linter.visit(parse(content))
|
12
14
|
|
13
|
-
return
|
15
|
+
return ftl_linter.results
|
14
16
|
|
15
17
|
def testPS01_valid(self):
|
16
18
|
content = """
|
@@ -1,16 +1,18 @@
|
|
1
1
|
import unittest
|
2
|
-
|
2
|
+
|
3
3
|
from fluent.syntax import parse
|
4
4
|
|
5
|
+
from src.fluent_linter import linter
|
6
|
+
|
5
7
|
|
6
8
|
class TestSyntax(unittest.TestCase):
|
7
9
|
def checkContent(self, config, content):
|
8
|
-
|
10
|
+
ftl_linter = linter.Linter(
|
9
11
|
"path", "root", config, content, linter.get_offsets_and_lines(content)
|
10
12
|
)
|
11
|
-
|
13
|
+
ftl_linter.visit(parse(content))
|
12
14
|
|
13
|
-
return
|
15
|
+
return ftl_linter.results
|
14
16
|
|
15
17
|
def testSY01(self):
|
16
18
|
content = """
|
@@ -0,0 +1,222 @@
|
|
1
|
+
import unittest
|
2
|
+
|
3
|
+
from fluent.syntax import parse
|
4
|
+
|
5
|
+
from src.fluent_linter import linter
|
6
|
+
|
7
|
+
|
8
|
+
class TestTypography(unittest.TestCase):
|
9
|
+
def checkContent(self, config, content):
|
10
|
+
ftl_linter = linter.Linter(
|
11
|
+
"path", "root", config, content, linter.get_offsets_and_lines(content)
|
12
|
+
)
|
13
|
+
ftl_linter.visit(parse(content))
|
14
|
+
|
15
|
+
return ftl_linter.results
|
16
|
+
|
17
|
+
def testTE01(self):
|
18
|
+
content = """
|
19
|
+
foo = bar's bar
|
20
|
+
"""
|
21
|
+
results = self.checkContent({}, content)
|
22
|
+
self.assertEqual(len(results), 1)
|
23
|
+
self.assertTrue("TE01" in results[0])
|
24
|
+
self.assertTrue("foo" in results[0])
|
25
|
+
|
26
|
+
# Check exclusions
|
27
|
+
config = {"TE01": {"exclusions": {"messages": ["foo"]}}}
|
28
|
+
results = self.checkContent(config, content)
|
29
|
+
self.assertEqual(len(results), 0)
|
30
|
+
|
31
|
+
content = """
|
32
|
+
foo = bar ' bar
|
33
|
+
"""
|
34
|
+
results = self.checkContent({}, content)
|
35
|
+
self.assertEqual(len(results), 0)
|
36
|
+
|
37
|
+
def testTE02(self):
|
38
|
+
content = """
|
39
|
+
foo = bar‘s bar
|
40
|
+
"""
|
41
|
+
results = self.checkContent({}, content)
|
42
|
+
self.assertEqual(len(results), 1)
|
43
|
+
self.assertTrue("TE02" in results[0])
|
44
|
+
self.assertTrue("foo" in results[0])
|
45
|
+
|
46
|
+
# Check exclusions
|
47
|
+
config = {"TE02": {"exclusions": {"messages": ["foo"]}}}
|
48
|
+
results = self.checkContent(config, content)
|
49
|
+
self.assertEqual(len(results), 0)
|
50
|
+
|
51
|
+
content = """
|
52
|
+
foo = bar ‘ bar
|
53
|
+
"""
|
54
|
+
results = self.checkContent({}, content)
|
55
|
+
self.assertEqual(len(results), 0)
|
56
|
+
|
57
|
+
def testTE03(self):
|
58
|
+
content = """
|
59
|
+
foo = bar 'bar' bar
|
60
|
+
"""
|
61
|
+
results = self.checkContent({}, content)
|
62
|
+
self.assertEqual(len(results), 2)
|
63
|
+
self.assertTrue("TE01" in results[0])
|
64
|
+
self.assertTrue("TE03" in results[1])
|
65
|
+
self.assertTrue("foo" in results[0])
|
66
|
+
|
67
|
+
# Check exclusions
|
68
|
+
config = {
|
69
|
+
"TE01": {"exclusions": {"messages": ["foo"]}},
|
70
|
+
"TE03": {"exclusions": {"messages": ["foo"]}},
|
71
|
+
}
|
72
|
+
results = self.checkContent(config, content)
|
73
|
+
self.assertEqual(len(results), 0)
|
74
|
+
|
75
|
+
def testTE04(self):
|
76
|
+
content = """
|
77
|
+
foo = bar "bar" bar
|
78
|
+
# This shouldn't trigger an error
|
79
|
+
foo1 = { -someterm(capitalization: "uppercase") }
|
80
|
+
foo-datetime = Test: { DATETIME($timeChanged, day: "numeric", month: "long", year: "numeric") }
|
81
|
+
foo-number = { NUMBER($mem, maxFractionalUnits: 2) } MB
|
82
|
+
foo-empty = { "" }
|
83
|
+
foo-space = { "" } test
|
84
|
+
foo-curly1 = { "{" } test
|
85
|
+
foo-curly2 = { "}" } test
|
86
|
+
"""
|
87
|
+
results = self.checkContent({}, content)
|
88
|
+
self.assertEqual(len(results), 1)
|
89
|
+
self.assertTrue("TE04" in results[0])
|
90
|
+
self.assertTrue("foo" in results[0])
|
91
|
+
|
92
|
+
# Check exclusions
|
93
|
+
config = {"TE04": {"exclusions": {"messages": ["foo"]}}}
|
94
|
+
results = self.checkContent(config, content)
|
95
|
+
self.assertEqual(len(results), 0)
|
96
|
+
|
97
|
+
def testTE05(self):
|
98
|
+
content = """
|
99
|
+
foo = bar...
|
100
|
+
"""
|
101
|
+
results = self.checkContent({}, content)
|
102
|
+
self.assertEqual(len(results), 1)
|
103
|
+
self.assertTrue("TE05" in results[0])
|
104
|
+
|
105
|
+
# Check exclusions
|
106
|
+
config = {"TE05": {"exclusions": {"messages": ["foo"]}}}
|
107
|
+
results = self.checkContent(config, content)
|
108
|
+
self.assertEqual(len(results), 0)
|
109
|
+
|
110
|
+
content = """
|
111
|
+
foo = bar…
|
112
|
+
"""
|
113
|
+
results = self.checkContent({}, content)
|
114
|
+
self.assertEqual(len(results), 0)
|
115
|
+
|
116
|
+
def testTE01Disabled(self):
|
117
|
+
"""Test that TE01 can be disabled with enabled: false"""
|
118
|
+
content = """
|
119
|
+
foo = bar's bar
|
120
|
+
"""
|
121
|
+
# Rule enabled by default - should trigger error
|
122
|
+
results = self.checkContent({}, content)
|
123
|
+
self.assertEqual(len(results), 1)
|
124
|
+
self.assertTrue("TE01" in results[0])
|
125
|
+
|
126
|
+
# Rule explicitly disabled - should not trigger error
|
127
|
+
config = {"TE01": {"enabled": False}}
|
128
|
+
results = self.checkContent(config, content)
|
129
|
+
self.assertEqual(len(results), 0)
|
130
|
+
|
131
|
+
# Rule explicitly enabled - should trigger error
|
132
|
+
config = {"TE01": {"enabled": True}}
|
133
|
+
results = self.checkContent(config, content)
|
134
|
+
self.assertEqual(len(results), 1)
|
135
|
+
self.assertTrue("TE01" in results[0])
|
136
|
+
|
137
|
+
def testTE02Disabled(self):
|
138
|
+
"""Test that TE02 can be disabled with enabled: false"""
|
139
|
+
content = """
|
140
|
+
foo = bar‘s bar
|
141
|
+
"""
|
142
|
+
# Rule enabled by default - should trigger error
|
143
|
+
results = self.checkContent({}, content)
|
144
|
+
self.assertEqual(len(results), 1)
|
145
|
+
self.assertTrue("TE02" in results[0])
|
146
|
+
|
147
|
+
# Rule explicitly disabled - should not trigger error
|
148
|
+
config = {"TE02": {"enabled": False}}
|
149
|
+
results = self.checkContent(config, content)
|
150
|
+
self.assertEqual(len(results), 0)
|
151
|
+
|
152
|
+
# Rule explicitly enabled - should trigger error
|
153
|
+
config = {"TE02": {"enabled": True}}
|
154
|
+
results = self.checkContent(config, content)
|
155
|
+
self.assertEqual(len(results), 1)
|
156
|
+
self.assertTrue("TE02" in results[0])
|
157
|
+
|
158
|
+
def testTE03Disabled(self):
|
159
|
+
"""Test that TE03 can be disabled with enabled: false"""
|
160
|
+
content = """
|
161
|
+
foo = bar 'test' bar
|
162
|
+
"""
|
163
|
+
# Rule enabled by default - should trigger errors (TE01 and TE03)
|
164
|
+
results = self.checkContent({}, content)
|
165
|
+
self.assertEqual(len(results), 2)
|
166
|
+
self.assertTrue("TE01" in results[0])
|
167
|
+
self.assertTrue("TE03" in results[1])
|
168
|
+
|
169
|
+
# TE03 explicitly disabled - should only get TE01 error
|
170
|
+
config = {"TE03": {"enabled": False}}
|
171
|
+
results = self.checkContent(config, content)
|
172
|
+
self.assertEqual(len(results), 1)
|
173
|
+
self.assertTrue("TE01" in results[0])
|
174
|
+
|
175
|
+
# TE03 explicitly enabled - should get both errors
|
176
|
+
config = {"TE03": {"enabled": True}}
|
177
|
+
results = self.checkContent(config, content)
|
178
|
+
self.assertEqual(len(results), 2)
|
179
|
+
self.assertTrue("TE01" in results[0])
|
180
|
+
self.assertTrue("TE03" in results[1])
|
181
|
+
|
182
|
+
def testTE04Disabled(self):
|
183
|
+
"""Test that TE04 can be disabled with enabled: false"""
|
184
|
+
content = """
|
185
|
+
foo = bar "test" bar
|
186
|
+
"""
|
187
|
+
# Rule enabled by default - should trigger error
|
188
|
+
results = self.checkContent({}, content)
|
189
|
+
self.assertEqual(len(results), 1)
|
190
|
+
self.assertTrue("TE04" in results[0])
|
191
|
+
|
192
|
+
# Rule explicitly disabled - should not trigger error
|
193
|
+
config = {"TE04": {"enabled": False}}
|
194
|
+
results = self.checkContent(config, content)
|
195
|
+
self.assertEqual(len(results), 0)
|
196
|
+
|
197
|
+
# Rule explicitly enabled - should trigger error
|
198
|
+
config = {"TE04": {"enabled": True}}
|
199
|
+
results = self.checkContent(config, content)
|
200
|
+
self.assertEqual(len(results), 1)
|
201
|
+
self.assertTrue("TE04" in results[0])
|
202
|
+
|
203
|
+
def testTE05Disabled(self):
|
204
|
+
"""Test that TE05 can be disabled with enabled: false"""
|
205
|
+
content = """
|
206
|
+
foo = bar...
|
207
|
+
"""
|
208
|
+
# Rule enabled by default - should trigger error
|
209
|
+
results = self.checkContent({}, content)
|
210
|
+
self.assertEqual(len(results), 1)
|
211
|
+
self.assertTrue("TE05" in results[0])
|
212
|
+
|
213
|
+
# Rule explicitly disabled - should not trigger error
|
214
|
+
config = {"TE05": {"enabled": False}}
|
215
|
+
results = self.checkContent(config, content)
|
216
|
+
self.assertEqual(len(results), 0)
|
217
|
+
|
218
|
+
# Rule explicitly enabled - should trigger error
|
219
|
+
config = {"TE05": {"enabled": True}}
|
220
|
+
results = self.checkContent(config, content)
|
221
|
+
self.assertEqual(len(results), 1)
|
222
|
+
self.assertTrue("TE05" in results[0])
|
@@ -1 +0,0 @@
|
|
1
|
-
version = "0.4.7"
|
@@ -1,112 +0,0 @@
|
|
1
|
-
import unittest
|
2
|
-
from src.fluent_linter import linter
|
3
|
-
from fluent.syntax import parse
|
4
|
-
|
5
|
-
|
6
|
-
class TestTypography(unittest.TestCase):
|
7
|
-
def checkContent(self, config, content):
|
8
|
-
l = linter.Linter(
|
9
|
-
"path", "root", config, content, linter.get_offsets_and_lines(content)
|
10
|
-
)
|
11
|
-
l.visit(parse(content))
|
12
|
-
|
13
|
-
return l.results
|
14
|
-
|
15
|
-
def testTE01(self):
|
16
|
-
content = """
|
17
|
-
foo = bar's bar
|
18
|
-
"""
|
19
|
-
results = self.checkContent({}, content)
|
20
|
-
self.assertEqual(len(results), 1)
|
21
|
-
self.assertTrue("TE01" in results[0])
|
22
|
-
self.assertTrue("foo" in results[0])
|
23
|
-
|
24
|
-
# Check exclusions
|
25
|
-
config = {"TE01": {"exclusions": {"messages": ["foo"]}}}
|
26
|
-
results = self.checkContent(config, content)
|
27
|
-
self.assertEqual(len(results), 0)
|
28
|
-
|
29
|
-
content = """
|
30
|
-
foo = bar ' bar
|
31
|
-
"""
|
32
|
-
results = self.checkContent({}, content)
|
33
|
-
self.assertEqual(len(results), 0)
|
34
|
-
|
35
|
-
def testTE02(self):
|
36
|
-
content = """
|
37
|
-
foo = bar‘s bar
|
38
|
-
"""
|
39
|
-
results = self.checkContent({}, content)
|
40
|
-
self.assertEqual(len(results), 1)
|
41
|
-
self.assertTrue("TE02" in results[0])
|
42
|
-
self.assertTrue("foo" in results[0])
|
43
|
-
|
44
|
-
# Check exclusions
|
45
|
-
config = {"TE02": {"exclusions": {"messages": ["foo"]}}}
|
46
|
-
results = self.checkContent(config, content)
|
47
|
-
self.assertEqual(len(results), 0)
|
48
|
-
|
49
|
-
content = """
|
50
|
-
foo = bar ‘ bar
|
51
|
-
"""
|
52
|
-
results = self.checkContent({}, content)
|
53
|
-
self.assertEqual(len(results), 0)
|
54
|
-
|
55
|
-
def testTE03(self):
|
56
|
-
content = """
|
57
|
-
foo = bar 'bar' bar
|
58
|
-
"""
|
59
|
-
results = self.checkContent({}, content)
|
60
|
-
self.assertEqual(len(results), 2)
|
61
|
-
self.assertTrue("TE01" in results[0])
|
62
|
-
self.assertTrue("TE03" in results[1])
|
63
|
-
self.assertTrue("foo" in results[0])
|
64
|
-
|
65
|
-
# Check exclusions
|
66
|
-
config = {
|
67
|
-
"TE01": {"exclusions": {"messages": ["foo"]}},
|
68
|
-
"TE03": {"exclusions": {"messages": ["foo"]}},
|
69
|
-
}
|
70
|
-
results = self.checkContent(config, content)
|
71
|
-
self.assertEqual(len(results), 0)
|
72
|
-
|
73
|
-
def testTE04(self):
|
74
|
-
content = """
|
75
|
-
foo = bar "bar" bar
|
76
|
-
# This shouldn't trigger an error
|
77
|
-
foo1 = { -someterm(capitalization: "uppercase") }
|
78
|
-
foo-datetime = Test: { DATETIME($timeChanged, day: "numeric", month: "long", year: "numeric") }
|
79
|
-
foo-number = { NUMBER($mem, maxFractionalUnits: 2) } MB
|
80
|
-
foo-empty = { "" }
|
81
|
-
foo-space = { "" } test
|
82
|
-
foo-curly1 = { "{" } test
|
83
|
-
foo-curly2 = { "}" } test
|
84
|
-
"""
|
85
|
-
results = self.checkContent({}, content)
|
86
|
-
self.assertEqual(len(results), 1)
|
87
|
-
self.assertTrue("TE04" in results[0])
|
88
|
-
self.assertTrue("foo" in results[0])
|
89
|
-
|
90
|
-
# Check exclusions
|
91
|
-
config = {"TE04": {"exclusions": {"messages": ["foo"]}}}
|
92
|
-
results = self.checkContent(config, content)
|
93
|
-
self.assertEqual(len(results), 0)
|
94
|
-
|
95
|
-
def testTE05(self):
|
96
|
-
content = """
|
97
|
-
foo = bar...
|
98
|
-
"""
|
99
|
-
results = self.checkContent({}, content)
|
100
|
-
self.assertEqual(len(results), 1)
|
101
|
-
self.assertTrue("TE05" in results[0])
|
102
|
-
|
103
|
-
# Check exclusions
|
104
|
-
config = {"TE05": {"exclusions": {"messages": ["foo"]}}}
|
105
|
-
results = self.checkContent(config, content)
|
106
|
-
self.assertEqual(len(results), 0)
|
107
|
-
|
108
|
-
content = """
|
109
|
-
foo = bar…
|
110
|
-
"""
|
111
|
-
results = self.checkContent({}, content)
|
112
|
-
self.assertEqual(len(results), 0)
|
File without changes
|
File without changes
|
{moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/SOURCES.txt
RENAMED
File without changes
|
File without changes
|
{moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/entry_points.txt
RENAMED
File without changes
|
{moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/requires.txt
RENAMED
File without changes
|
{moz_fluent_linter-0.4.7 → moz_fluent_linter-0.4.8}/src/moz_fluent_linter.egg-info/top_level.txt
RENAMED
File without changes
|