diff --git a/pom.xml b/pom.xml
index 18728b29..51f49581 100644
--- a/pom.xml
+++ b/pom.xml
@@ -212,6 +212,18 @@ SOFTWARE.
0.7.1
test
+
+ org.languagetool
+ language-en
+ 6.5
+ test
+
+
+ com.jcabi
+ jcabi-matchers
+ 1.8.0
+ test
+
diff --git a/src/main/resources/org/eolang/funcs/escape.xsl b/src/main/resources/org/eolang/funcs/escape.xsl
new file mode 100644
index 00000000..8bf026fa
--- /dev/null
+++ b/src/main/resources/org/eolang/funcs/escape.xsl
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
diff --git a/src/main/resources/org/eolang/lints/aliases/alias-too-long.xsl b/src/main/resources/org/eolang/lints/aliases/alias-too-long.xsl
index 41c654af..370c328a 100644
--- a/src/main/resources/org/eolang/lints/aliases/alias-too-long.xsl
+++ b/src/main/resources/org/eolang/lints/aliases/alias-too-long.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -36,9 +37,8 @@ SOFTWARE.
error
- The alias has too many parts: "
-
- "
+ The alias has too many parts:
+
diff --git a/src/main/resources/org/eolang/lints/aliases/broken-alias-first.xsl b/src/main/resources/org/eolang/lints/aliases/broken-alias-first.xsl
index 741d4a06..aa0c6ec8 100644
--- a/src/main/resources/org/eolang/lints/aliases/broken-alias-first.xsl
+++ b/src/main/resources/org/eolang/lints/aliases/broken-alias-first.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -36,9 +37,9 @@ SOFTWARE.
error
- The first part of the alias is invalid: "
-
- " (it may only contain a relative name of the object, not its FQN)
+ The first part of the alias is invalid:
+
+ (it may only contain a relative name of the object, not its FQN)
diff --git a/src/main/resources/org/eolang/lints/aliases/broken-alias-second.xsl b/src/main/resources/org/eolang/lints/aliases/broken-alias-second.xsl
index 8c340575..aec86023 100644
--- a/src/main/resources/org/eolang/lints/aliases/broken-alias-second.xsl
+++ b/src/main/resources/org/eolang/lints/aliases/broken-alias-second.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -36,9 +37,9 @@ SOFTWARE.
error
- The second part of the alias is invalid: "
-
- " (it may only contain FQN)
+ The second part of the alias is invalid:
+
+ (it may only contain FQN)
diff --git a/src/main/resources/org/eolang/lints/aliases/duplicate-aliases.xsl b/src/main/resources/org/eolang/lints/aliases/duplicate-aliases.xsl
index 5953ff85..0de729f0 100644
--- a/src/main/resources/org/eolang/lints/aliases/duplicate-aliases.xsl
+++ b/src/main/resources/org/eolang/lints/aliases/duplicate-aliases.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -37,9 +38,9 @@ SOFTWARE.
error
- The alias "
-
- " is duplicated
+ The alias
+
+ is duplicated
@@ -56,9 +57,9 @@ SOFTWARE.
error
- The name "
-
- " is already in use
+ The name
+
+ is already in use
diff --git a/src/main/resources/org/eolang/lints/aliases/unused-alias.xsl b/src/main/resources/org/eolang/lints/aliases/unused-alias.xsl
index 9f34d635..fab6480e 100644
--- a/src/main/resources/org/eolang/lints/aliases/unused-alias.xsl
+++ b/src/main/resources/org/eolang/lints/aliases/unused-alias.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -37,11 +38,10 @@ SOFTWARE.
error
- The alias "
-
- " is not used, but defined as "+alias
-
- "
+ The alias
+
+ is not used, but defined as
+
diff --git a/src/main/resources/org/eolang/lints/atoms/atom-and-base.xsl b/src/main/resources/org/eolang/lints/atoms/atom-and-base.xsl
index f29ec2a1..037f443d 100644
--- a/src/main/resources/org/eolang/lints/atoms/atom-and-base.xsl
+++ b/src/main/resources/org/eolang/lints/atoms/atom-and-base.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -35,11 +36,10 @@ SOFTWARE.
critical
- The atom "
-
- " may not have the "@base" attribute, which however exists with "
-
- "
+ The atom
+
+ may not have the "@base" attribute, which however exists with
+
diff --git a/src/main/resources/org/eolang/lints/atoms/atom-in-atom.xsl b/src/main/resources/org/eolang/lints/atoms/atom-in-atom.xsl
index bb1da3e1..07f7f5c8 100644
--- a/src/main/resources/org/eolang/lints/atoms/atom-in-atom.xsl
+++ b/src/main/resources/org/eolang/lints/atoms/atom-in-atom.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -35,16 +36,14 @@ SOFTWARE.
error
- Atom "
-
- " may not have any attributes, even if they are atoms, which however exist:
+ Atom
+
+ may not have any attributes, even if they are atoms, which however exist:
,
- "
-
- "
+
diff --git a/src/main/resources/org/eolang/lints/atoms/atom-without-rt.xsl b/src/main/resources/org/eolang/lints/atoms/atom-without-rt.xsl
index bab30c6b..7b72c983 100644
--- a/src/main/resources/org/eolang/lints/atoms/atom-without-rt.xsl
+++ b/src/main/resources/org/eolang/lints/atoms/atom-without-rt.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -36,9 +37,9 @@ SOFTWARE.
error
- The "
-
- " atom is defined without the +rt meta, which doesn't make any sense
+ The
+
+ atom is defined without the +rt meta, which doesn't make any sense
diff --git a/src/main/resources/org/eolang/lints/atoms/not-empty-atom.xsl b/src/main/resources/org/eolang/lints/atoms/not-empty-atom.xsl
index 2123ed09..8bfc255d 100644
--- a/src/main/resources/org/eolang/lints/atoms/not-empty-atom.xsl
+++ b/src/main/resources/org/eolang/lints/atoms/not-empty-atom.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -35,16 +36,14 @@ SOFTWARE.
error
- The atom "
-
- " may not have any attributes, which however exist:
+ The atom
+
+ may not have any attributes, which however exist:
,
- "
-
- "
+
diff --git a/src/main/resources/org/eolang/lints/comments/comment-is-too-wide.xsl b/src/main/resources/org/eolang/lints/comments/comment-is-too-wide.xsl
index 7f5b0b42..0946322a 100644
--- a/src/main/resources/org/eolang/lints/comments/comment-is-too-wide.xsl
+++ b/src/main/resources/org/eolang/lints/comments/comment-is-too-wide.xsl
@@ -41,11 +41,11 @@ SOFTWARE.
warning
- The comment line width is "
+ The comment line width is
- ", while "
+ , while
- " is max allowed
+ is max allowed
@@ -58,11 +58,11 @@ SOFTWARE.
warning
- The comment width is "
+ The comment width is
- ", while "
+ , while
- " is max allowed
+ is max allowed
diff --git a/src/main/resources/org/eolang/lints/critical/atom-with-data.xsl b/src/main/resources/org/eolang/lints/critical/atom-with-data.xsl
index 2f66f8e3..99d1e105 100644
--- a/src/main/resources/org/eolang/lints/critical/atom-with-data.xsl
+++ b/src/main/resources/org/eolang/lints/critical/atom-with-data.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -38,9 +39,8 @@ SOFTWARE.
critical
- Atoms must not contain data, while this object contains "
-
- "
+ Atoms must not contain data, while this object contains
+
diff --git a/src/main/resources/org/eolang/lints/critical/duplicate-names.xsl b/src/main/resources/org/eolang/lints/critical/duplicate-names.xsl
index 484cf1bd..98d1e7f2 100644
--- a/src/main/resources/org/eolang/lints/critical/duplicate-names.xsl
+++ b/src/main/resources/org/eolang/lints/critical/duplicate-names.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -43,9 +44,9 @@ SOFTWARE.
critical
- The name "
-
- " is already in use
+ The name
+
+ is already in use
diff --git a/src/main/resources/org/eolang/lints/critical/incorrect-bytes-format.xsl b/src/main/resources/org/eolang/lints/critical/incorrect-bytes-format.xsl
index c20820bc..145d2e8a 100644
--- a/src/main/resources/org/eolang/lints/critical/incorrect-bytes-format.xsl
+++ b/src/main/resources/org/eolang/lints/critical/incorrect-bytes-format.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -38,9 +39,8 @@ SOFTWARE.
critical
- The format of bytes is incorrect: "
-
- "
+ The format of bytes is incorrect:
+
diff --git a/src/main/resources/org/eolang/lints/critical/object-has-data.xsl b/src/main/resources/org/eolang/lints/critical/object-has-data.xsl
index c9e78c34..1243f830 100644
--- a/src/main/resources/org/eolang/lints/critical/object-has-data.xsl
+++ b/src/main/resources/org/eolang/lints/critical/object-has-data.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -38,7 +39,8 @@ SOFTWARE.
critical
- Only objects with their @base attributes containing 'org.eolang.bytes' may contain data, while this object doesn't have @base attribute at all
+ Only objects with their @base attributes containing "org.eolang.bytes" may contain data,
+ while this object doesn't have @base attribute at all
@@ -47,9 +49,9 @@ SOFTWARE.
critical
- Only objects with their @base attributes containing 'org.eolang.bytes' may contain data, while this object contains "
-
- "
+ Only objects with their @base attributes containing "org.eolang.bytes" may contain data,
+ while this object contains
+
diff --git a/src/main/resources/org/eolang/lints/critical/pos-without-line.xsl b/src/main/resources/org/eolang/lints/critical/pos-without-line.xsl
index 2bfe9ea3..28144e12 100644
--- a/src/main/resources/org/eolang/lints/critical/pos-without-line.xsl
+++ b/src/main/resources/org/eolang/lints/critical/pos-without-line.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -35,9 +36,9 @@ SOFTWARE.
critical
- Object "
+ Object
- " have '@pos', but '@line' is absent
+ have the "@pos" attribute, but the "@line" attribute is absent
diff --git a/src/main/resources/org/eolang/lints/critical/same-line-names.xsl b/src/main/resources/org/eolang/lints/critical/same-line-names.xsl
index ee447364..1702e124 100644
--- a/src/main/resources/org/eolang/lints/critical/same-line-names.xsl
+++ b/src/main/resources/org/eolang/lints/critical/same-line-names.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -42,9 +43,9 @@ SOFTWARE.
error
- The name "
-
- " has been used twice on line no.
+ The name
+
+ has been used twice on line no.
diff --git a/src/main/resources/org/eolang/lints/critical/schema-is-absent.xsl b/src/main/resources/org/eolang/lints/critical/schema-is-absent.xsl
index 4d901de5..321a4de6 100644
--- a/src/main/resources/org/eolang/lints/critical/schema-is-absent.xsl
+++ b/src/main/resources/org/eolang/lints/critical/schema-is-absent.xsl
@@ -39,7 +39,7 @@ SOFTWARE.
critical
There is no XSD schema attached to the XML document,
- while xsi:noNamespaceSchemaLocation is expected
+ while "xsi:noNamespaceSchemaLocation" is expected
diff --git a/src/main/resources/org/eolang/lints/critical/self-naming.xsl b/src/main/resources/org/eolang/lints/critical/self-naming.xsl
index 4c6f569f..e52fc1ff 100644
--- a/src/main/resources/org/eolang/lints/critical/self-naming.xsl
+++ b/src/main/resources/org/eolang/lints/critical/self-naming.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -55,9 +56,9 @@ SOFTWARE.
error
- The object "
-
- " can't copy itself
+ The object
+
+ can't copy itself
diff --git a/src/main/resources/org/eolang/lints/critical/unknown-rt.xsl b/src/main/resources/org/eolang/lints/critical/unknown-rt.xsl
index cb749971..63f01ea7 100644
--- a/src/main/resources/org/eolang/lints/critical/unknown-rt.xsl
+++ b/src/main/resources/org/eolang/lints/critical/unknown-rt.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -49,16 +50,14 @@ SOFTWARE.
critical
- The runtime "
-
- " is not supported (only
+ The runtime
+
+ is not supported (only
,
- "
-
- "
+
)
diff --git a/src/main/resources/org/eolang/lints/errors/empty-object.xsl b/src/main/resources/org/eolang/lints/errors/empty-object.xsl
index 6f0c54a4..bd8ef359 100644
--- a/src/main/resources/org/eolang/lints/errors/empty-object.xsl
+++ b/src/main/resources/org/eolang/lints/errors/empty-object.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -39,9 +40,7 @@ SOFTWARE.
object
- "
-
- "
+
anonymous object
diff --git a/src/main/resources/org/eolang/lints/errors/many-free-attributes.xsl b/src/main/resources/org/eolang/lints/errors/many-free-attributes.xsl
index fe41ac41..20172703 100644
--- a/src/main/resources/org/eolang/lints/errors/many-free-attributes.xsl
+++ b/src/main/resources/org/eolang/lints/errors/many-free-attributes.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -37,10 +38,8 @@ SOFTWARE.
warning
The object
- "
-
- "
- has more than
+
+ has more than
free attributes, it's too many
diff --git a/src/main/resources/org/eolang/lints/errors/noname-attribute.xsl b/src/main/resources/org/eolang/lints/errors/noname-attribute.xsl
index 173d1fb0..28ae8bd0 100644
--- a/src/main/resources/org/eolang/lints/errors/noname-attribute.xsl
+++ b/src/main/resources/org/eolang/lints/errors/noname-attribute.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -44,9 +45,8 @@ SOFTWARE.
The object
- "
-
- "
+
+
has an attribute without a name
diff --git a/src/main/resources/org/eolang/lints/errors/unknown-name.xsl b/src/main/resources/org/eolang/lints/errors/unknown-name.xsl
index 58c38216..55b131d0 100644
--- a/src/main/resources/org/eolang/lints/errors/unknown-name.xsl
+++ b/src/main/resources/org/eolang/lints/errors/unknown-name.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -35,9 +36,9 @@ SOFTWARE.
error
- The object "
-
- " is not defined anywhere
+ The object
+
+ is not defined anywhere
diff --git a/src/main/resources/org/eolang/lints/lines/error-line-out-of-listing.xsl b/src/main/resources/org/eolang/lints/lines/error-line-out-of-listing.xsl
index a492ed30..99cf1ed4 100644
--- a/src/main/resources/org/eolang/lints/lines/error-line-out-of-listing.xsl
+++ b/src/main/resources/org/eolang/lints/lines/error-line-out-of-listing.xsl
@@ -36,9 +36,9 @@ SOFTWARE.
error
- The line "
+ The line
- " is out of listing, which contains only
+ is out of listing, which contains only
lines
diff --git a/src/main/resources/org/eolang/lints/lines/meta-line-out-of-listing.xsl b/src/main/resources/org/eolang/lints/lines/meta-line-out-of-listing.xsl
index fac6e6cf..a751c62c 100644
--- a/src/main/resources/org/eolang/lints/lines/meta-line-out-of-listing.xsl
+++ b/src/main/resources/org/eolang/lints/lines/meta-line-out-of-listing.xsl
@@ -36,9 +36,9 @@ SOFTWARE.
error
- The line "
+ The line
- " is out of listing, which contains only
+ is out of listing, which contains only
lines
diff --git a/src/main/resources/org/eolang/lints/lines/object-line-out-of-listing.xsl b/src/main/resources/org/eolang/lints/lines/object-line-out-of-listing.xsl
index 17e3e414..c1fad492 100644
--- a/src/main/resources/org/eolang/lints/lines/object-line-out-of-listing.xsl
+++ b/src/main/resources/org/eolang/lints/lines/object-line-out-of-listing.xsl
@@ -36,9 +36,9 @@ SOFTWARE.
error
- The line "
+ The line
- " is out of listing, which contains only
+ is out of listing, which contains only
lines
diff --git a/src/main/resources/org/eolang/lints/metas/duplicate-metas.xsl b/src/main/resources/org/eolang/lints/metas/duplicate-metas.xsl
index 09689f44..c3eea4da 100644
--- a/src/main/resources/org/eolang/lints/metas/duplicate-metas.xsl
+++ b/src/main/resources/org/eolang/lints/metas/duplicate-metas.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -38,9 +39,9 @@ SOFTWARE.
warning
- The meta "
-
- " is seen more than once
+ The meta
+
+ is seen more than once
diff --git a/src/main/resources/org/eolang/lints/metas/incorrect-architect.xsl b/src/main/resources/org/eolang/lints/metas/incorrect-architect.xsl
index b0c8dea0..8e79782a 100644
--- a/src/main/resources/org/eolang/lints/metas/incorrect-architect.xsl
+++ b/src/main/resources/org/eolang/lints/metas/incorrect-architect.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -38,9 +39,8 @@ SOFTWARE.
warning
- The format of the email in the +architect meta is wrong: "
-
- "
+ The format of the email in the +architect meta is wrong:
+
diff --git a/src/main/resources/org/eolang/lints/metas/incorrect-home.xsl b/src/main/resources/org/eolang/lints/metas/incorrect-home.xsl
index fa79181a..2b1c9e6e 100644
--- a/src/main/resources/org/eolang/lints/metas/incorrect-home.xsl
+++ b/src/main/resources/org/eolang/lints/metas/incorrect-home.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -38,9 +39,8 @@ SOFTWARE.
warning
- The format of the URL at the +home meta is wrong: "
-
- "
+ The format of the URL at the +home meta is wrong:
+
diff --git a/src/main/resources/org/eolang/lints/metas/incorrect-jvm-rt-location.xsl b/src/main/resources/org/eolang/lints/metas/incorrect-jvm-rt-location.xsl
index e099505e..8aba24e5 100644
--- a/src/main/resources/org/eolang/lints/metas/incorrect-jvm-rt-location.xsl
+++ b/src/main/resources/org/eolang/lints/metas/incorrect-jvm-rt-location.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -39,9 +40,8 @@ SOFTWARE.
warning
- The format of the location of jvm runtime is wrong: "
-
- "
+ The format of the location of the "jvm" runtime is wrong:
+
diff --git a/src/main/resources/org/eolang/lints/metas/incorrect-node-rt-location.xsl b/src/main/resources/org/eolang/lints/metas/incorrect-node-rt-location.xsl
index dcac81da..e311714d 100644
--- a/src/main/resources/org/eolang/lints/metas/incorrect-node-rt-location.xsl
+++ b/src/main/resources/org/eolang/lints/metas/incorrect-node-rt-location.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -39,9 +40,8 @@ SOFTWARE.
warning
- The format of the location of node runtime is wrong: "
-
- "
+ The format of the location of node runtime is wrong:
+
diff --git a/src/main/resources/org/eolang/lints/metas/incorrect-package.xsl b/src/main/resources/org/eolang/lints/metas/incorrect-package.xsl
index ca5a1575..66df6611 100644
--- a/src/main/resources/org/eolang/lints/metas/incorrect-package.xsl
+++ b/src/main/resources/org/eolang/lints/metas/incorrect-package.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -39,9 +40,8 @@ SOFTWARE.
warning
- The format of the +package meta is wrong: "
-
- "
+ The format of the +package meta is wrong:
+
diff --git a/src/main/resources/org/eolang/lints/metas/incorrect-version.xsl b/src/main/resources/org/eolang/lints/metas/incorrect-version.xsl
index 8f9af678..6ac4c427 100644
--- a/src/main/resources/org/eolang/lints/metas/incorrect-version.xsl
+++ b/src/main/resources/org/eolang/lints/metas/incorrect-version.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -38,9 +39,9 @@ SOFTWARE.
warning
- The format of the +version meta is wrong: "
-
- " (SemVer expected instead)
+ The format of the +version meta is wrong:
+
+ (SemVer expected instead)
diff --git a/src/main/resources/org/eolang/lints/metas/unknown-metas.xsl b/src/main/resources/org/eolang/lints/metas/unknown-metas.xsl
index cca607ba..90c38692 100644
--- a/src/main/resources/org/eolang/lints/metas/unknown-metas.xsl
+++ b/src/main/resources/org/eolang/lints/metas/unknown-metas.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -38,9 +39,9 @@ SOFTWARE.
warning
- The meta "
-
- " is not supported and its usage has no effect
+ The meta
+
+ is not supported, and its usage has no effect
diff --git a/src/main/resources/org/eolang/lints/metas/unsorted-metas.xsl b/src/main/resources/org/eolang/lints/metas/unsorted-metas.xsl
index 8bb9d617..601ce10f 100644
--- a/src/main/resources/org/eolang/lints/metas/unsorted-metas.xsl
+++ b/src/main/resources/org/eolang/lints/metas/unsorted-metas.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -39,9 +40,9 @@ SOFTWARE.
warning
- The "
-
- " meta is out of order
+ The
+
+ meta is out of order
diff --git a/src/main/resources/org/eolang/lints/metas/zero-version.xsl b/src/main/resources/org/eolang/lints/metas/zero-version.xsl
index 52620ba7..32899da5 100644
--- a/src/main/resources/org/eolang/lints/metas/zero-version.xsl
+++ b/src/main/resources/org/eolang/lints/metas/zero-version.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -37,9 +38,8 @@ SOFTWARE.
error
- This +version may be used only during development: "
-
- "
+ This +version may be used only during development:
+
diff --git a/src/main/resources/org/eolang/lints/misc/incorrect-test-object-name.xsl b/src/main/resources/org/eolang/lints/misc/incorrect-test-object-name.xsl
index 69178627..eef3fc60 100644
--- a/src/main/resources/org/eolang/lints/misc/incorrect-test-object-name.xsl
+++ b/src/main/resources/org/eolang/lints/misc/incorrect-test-object-name.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -36,12 +37,10 @@ SOFTWARE.
warning
- The name of the object "
-
- "
- doesn't match "
-
- "
+ The name of the object
+
+ doesn't match
+
diff --git a/src/main/resources/org/eolang/lints/misc/one-high-level-object.xsl b/src/main/resources/org/eolang/lints/misc/one-high-level-object.xsl
index 468de86d..05937d0d 100644
--- a/src/main/resources/org/eolang/lints/misc/one-high-level-object.xsl
+++ b/src/main/resources/org/eolang/lints/misc/one-high-level-object.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -36,9 +37,9 @@ SOFTWARE.
warning
- Program "
-
- " has
+ Program
+
+ has
objects, while only 1 is allowed
diff --git a/src/main/resources/org/eolang/lints/names/object-does-not-match-filename.xsl b/src/main/resources/org/eolang/lints/names/object-does-not-match-filename.xsl
index ef6a189a..6bd4bdeb 100644
--- a/src/main/resources/org/eolang/lints/names/object-does-not-match-filename.xsl
+++ b/src/main/resources/org/eolang/lints/names/object-does-not-match-filename.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -50,11 +51,10 @@ SOFTWARE.
warning
- Object "
-
- " does not match with filename "
-
- "
+ Object
+
+ does not match with filename
+
diff --git a/src/main/resources/org/eolang/lints/refs/broken-ref.xsl b/src/main/resources/org/eolang/lints/refs/broken-ref.xsl
index d45c84f5..01eb831b 100644
--- a/src/main/resources/org/eolang/lints/refs/broken-ref.xsl
+++ b/src/main/resources/org/eolang/lints/refs/broken-ref.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -37,11 +38,10 @@ SOFTWARE.
- The object "
-
- " is absent, but is referenced as "
-
- "
+ The object
+
+ is absent, but is referenced as
+
diff --git a/src/main/resources/org/eolang/lints/refs/line-is-absent.xsl b/src/main/resources/org/eolang/lints/refs/line-is-absent.xsl
index c7f580ff..fc6a31b4 100644
--- a/src/main/resources/org/eolang/lints/refs/line-is-absent.xsl
+++ b/src/main/resources/org/eolang/lints/refs/line-is-absent.xsl
@@ -37,7 +37,7 @@ SOFTWARE.
-
+
The @line attribute is absent at
diff --git a/src/main/resources/org/eolang/lints/tests/unit-test-without-phi.xsl b/src/main/resources/org/eolang/lints/tests/unit-test-without-phi.xsl
index 20054e49..a69f1932 100644
--- a/src/main/resources/org/eolang/lints/tests/unit-test-without-phi.xsl
+++ b/src/main/resources/org/eolang/lints/tests/unit-test-without-phi.xsl
@@ -24,6 +24,7 @@ SOFTWARE.
-->
+
@@ -35,9 +36,8 @@ SOFTWARE.
warning
- The unit test doesn't have "@" attribute: "
-
- "
+ The unit test doesn't have "@" attribute:
+
diff --git a/src/test/java/org/eolang/lints/DefectMatcher.java b/src/test/java/org/eolang/lints/DefectMatcher.java
new file mode 100644
index 00000000..fe423fba
--- /dev/null
+++ b/src/test/java/org/eolang/lints/DefectMatcher.java
@@ -0,0 +1,68 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2024 Objectionary.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.eolang.lints;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+
+/**
+ * Hamcrest matcher for a single defect.
+ *
+ * @since 0.0.34
+ */
+final class DefectMatcher extends BaseMatcher {
+
+ /**
+ * Synthetic matcher that is built when input arrives.
+ */
+ private final List> matchers = new ArrayList<>(0);
+
+ @Override
+ public boolean matches(final Object input) {
+ final Defect defect = (Defect) input;
+ return this.saved(Matchers.greaterThanOrEqualTo(0)).matches(defect.line())
+ && this.saved(Matchers.not(Matchers.emptyString())).matches(defect.text())
+ && this.saved(new GrammarMatcher()).matches(defect.text());
+ }
+
+ @Override
+ public void describeTo(final Description desc) {
+ for (int idx = 0; idx < this.matchers.size(); ++idx) {
+ if (idx > 0) {
+ desc.appendText(" and ");
+ }
+ final Matcher> matcher = this.matchers.get(idx);
+ matcher.describeTo(desc);
+ }
+ }
+
+ private Matcher> saved(final Matcher> matcher) {
+ this.matchers.add(matcher);
+ return matcher;
+ }
+}
diff --git a/src/test/java/org/eolang/lints/DefectsMatcher.java b/src/test/java/org/eolang/lints/DefectsMatcher.java
new file mode 100644
index 00000000..311a8187
--- /dev/null
+++ b/src/test/java/org/eolang/lints/DefectsMatcher.java
@@ -0,0 +1,68 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2024 Objectionary.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.eolang.lints;
+
+import com.jcabi.xml.XML;
+import java.util.Collection;
+import java.util.LinkedList;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.hamcrest.Matcher;
+import org.hamcrest.Matchers;
+
+/**
+ * Hamcrest matcher for defects in XML.
+ *
+ * @since 0.0.34
+ */
+final class DefectsMatcher extends BaseMatcher {
+
+ /**
+ * Synthetic matcher that is built when input arrives.
+ */
+ private Matcher> matcher;
+
+ @Override
+ public boolean matches(final Object xml) {
+ final Collection defects = new LinkedList<>();
+ for (final XML defect : ((XML) xml).nodes("/defects/defect")) {
+ defects.add(
+ new Defect.Default(
+ "unknown",
+ Severity.parsed(defect.xpath("@severity").get(0)),
+ "unknown",
+ Integer.parseInt(defect.xpath("@line").get(0)),
+ defect.xpath("text()").get(0)
+ )
+ );
+ }
+ this.matcher = Matchers.everyItem(new DefectMatcher());
+ return this.matcher.matches(defects);
+ }
+
+ @Override
+ public void describeTo(final Description desc) {
+ this.matcher.describeTo(desc);
+ }
+}
diff --git a/src/test/java/org/eolang/lints/GrammarMatcher.java b/src/test/java/org/eolang/lints/GrammarMatcher.java
new file mode 100644
index 00000000..cedc2dad
--- /dev/null
+++ b/src/test/java/org/eolang/lints/GrammarMatcher.java
@@ -0,0 +1,122 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2016-2024 Objectionary.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+package org.eolang.lints;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import org.hamcrest.BaseMatcher;
+import org.hamcrest.Description;
+import org.languagetool.JLanguageTool;
+import org.languagetool.Languages;
+import org.languagetool.markup.AnnotatedText;
+import org.languagetool.markup.AnnotatedTextBuilder;
+import org.languagetool.rules.Rule;
+import org.languagetool.rules.RuleMatch;
+import org.languagetool.rules.spelling.SpellingCheckRule;
+
+/**
+ * Hamcrest matcher for a single piece of text, to make sure it's
+ * grammatically valid.
+ *
+ * @since 0.0.34
+ */
+final class GrammarMatcher extends BaseMatcher {
+
+ /**
+ * The item to be matched.
+ */
+ private String input;
+
+ /**
+ * Errors.
+ */
+ private List errors;
+
+ @Override
+ public boolean matches(final Object obj) {
+ final JLanguageTool tool = new JLanguageTool(
+ Languages.getLanguageForShortCode("en-GB")
+ );
+ for (final Rule rule : tool.getAllActiveRules()) {
+ if (rule instanceof SpellingCheckRule) {
+ ((SpellingCheckRule) rule).addIgnoreTokens(
+ Arrays.asList("decoratee", "eolang")
+ );
+ }
+ }
+ this.input = obj.toString();
+ try {
+ this.errors = tool.check(GrammarMatcher.annotated(this.input));
+ } catch (final IOException ex) {
+ throw new IllegalArgumentException(ex);
+ }
+ return this.errors.isEmpty();
+ }
+
+ @Override
+ public void describeTo(final Description desc) {
+ for (int idx = 0; idx < this.errors.size(); ++idx) {
+ if (idx > 0) {
+ desc.appendText(" and ");
+ }
+ final RuleMatch match = this.errors.get(idx);
+ desc.appendText("\n")
+ .appendValue(match.getRule().getId())
+ .appendText(" (")
+ .appendText(match.getMessage())
+ .appendText(") at ")
+ .appendText(Integer.toString(match.getFromPos()))
+ .appendText("-")
+ .appendText(Integer.toString(match.getToPos()))
+ .appendText(" in:\n ")
+ .appendText(this.input)
+ .appendText("\n annotated input:\n ")
+ .appendText(GrammarMatcher.annotated(this.input).toString())
+ .appendText("\n suggested correction(s):\n ")
+ .appendValue(match.getSuggestedReplacements());
+ }
+ }
+
+ private static AnnotatedText annotated(final String text) {
+ final AnnotatedTextBuilder builder = new AnnotatedTextBuilder();
+ final Pattern pattern = Pattern.compile("\"([^\"]+)\"");
+ final Matcher matcher = pattern.matcher(text);
+ int last = 0;
+ while (matcher.find()) {
+ final int start = matcher.start();
+ if (start > last) {
+ builder.addText(text.substring(last, start));
+ }
+ builder.addMarkup("\"").addText("text skipped").addMarkup("\"");
+ last = matcher.end();
+ }
+ if (last < text.length()) {
+ builder.addText(text.substring(last));
+ }
+ return builder.build();
+ }
+}
diff --git a/src/test/java/org/eolang/lints/LtByXslTest.java b/src/test/java/org/eolang/lints/LtByXslTest.java
index 84384b15..383445db 100644
--- a/src/test/java/org/eolang/lints/LtByXslTest.java
+++ b/src/test/java/org/eolang/lints/LtByXslTest.java
@@ -23,6 +23,7 @@
*/
package org.eolang.lints;
+import com.jcabi.matchers.XhtmlMatchers;
import com.jcabi.xml.XMLDocument;
import java.io.IOException;
import java.nio.file.Files;
@@ -31,6 +32,8 @@
import java.util.Set;
import java.util.stream.Collectors;
import org.cactoos.io.InputOf;
+import org.cactoos.text.TextOf;
+import org.cactoos.text.UncheckedText;
import org.eolang.jeo.Disassembler;
import org.eolang.jucs.ClasspathSource;
import org.eolang.parser.EoSyntax;
@@ -58,7 +61,7 @@ final class LtByXslTest {
@Test
void lintsOneFile() throws IOException {
MatcherAssert.assertThat(
- "the objects is found",
+ "No defects found, while a few of them expected",
new LtByXsl("critical/duplicate-names").defects(
new EoSyntax(
new InputOf("# first\n[] > foo\n# first\n[] > foo\n")
@@ -72,14 +75,14 @@ void lintsOneFile() throws IOException {
@ClasspathSource(value = "org/eolang/lints/packs/", glob = "**.yaml")
void testsAllLintsByEo(final String yaml) {
MatcherAssert.assertThat(
- "must pass without errors",
+ "Doesn't tell the story as it's expected",
new XtSticky(
new XtYaml(
yaml,
eo -> new EoSyntax("pack", new InputOf(eo)).parsed()
)
),
- new XtoryMatcher()
+ new XtoryMatcher(new DefectsMatcher())
);
}
@@ -176,6 +179,27 @@ void checksFileNaming() throws IOException {
);
}
+ @Test
+ void checksIdsInXslStylesheets() throws IOException {
+ Files.walk(Paths.get("src/main/resources/org/eolang/lints"))
+ .filter(Files::isRegularFile)
+ .filter(file -> file.getFileName().toString().endsWith(".xsl"))
+ .forEach(
+ path -> MatcherAssert.assertThat(
+ String.format("@id is wrong in: %s", path),
+ XhtmlMatchers.xhtml(
+ new UncheckedText(new TextOf(path)).asString()
+ ),
+ XhtmlMatchers.hasXPath(
+ String.format(
+ "/xsl:stylesheet[@id='%s']",
+ path.getFileName().toString().replaceAll("\\.xsl$", "")
+ )
+ )
+ )
+ );
+ }
+
@Test
@Timeout(30L)
void checksEmptyObjectOnLargeXmirInReasonableTime(@TempDir final Path tmp) throws IOException {