Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions src/main/java/org/eolang/lints/Fix.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
* SPDX-License-Identifier: MIT
*/
package org.eolang.lints;

import com.jcabi.xml.XML;
import java.io.IOException;

/**
* A fix for a lint defect.
* @since 0.2.1
*/
@FunctionalInterface
public interface Fix {

/**
* Apply the fix and return the corrected XMIR.
* @param xmir The XMIR to fix
* @return Fixed XMIR
* @throws IOException If something goes wrong
*/
XML apply(XML xmir) throws IOException;
}
52 changes: 52 additions & 0 deletions src/main/java/org/eolang/lints/FxUnsortedMetas.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
* SPDX-License-Identifier: MIT
*/
package org.eolang.lints;

import com.jcabi.xml.ClasspathSources;
import com.jcabi.xml.XML;
import com.jcabi.xml.XSL;
import com.jcabi.xml.XSLDocument;
import java.io.IOException;
import org.cactoos.io.ResourceOf;
import org.cactoos.scalar.Sticky;
import org.cactoos.scalar.Unchecked;
import org.cactoos.text.IoCheckedText;
import org.cactoos.text.TextOf;

/**
* Fix for the {@code unsorted-metas} lint.
* Sorts {@code meta} elements inside {@code metas} alphabetically
* by their {@code head} and {@code tail} content.
* @since 0.2.1
*/
public final class FxUnsortedMetas implements Fix {

/**
* The XSL stylesheet.
*/
private final Unchecked<XSL> sheet;

/**
* Ctor.
*/
public FxUnsortedMetas() {
this.sheet = new Unchecked<>(
new Sticky<>(
() -> new XSLDocument(
new IoCheckedText(
new TextOf(
new ResourceOf("org/eolang/fixes/metas/unsorted-metas.xsl")
)
).asString()
).with(new ClasspathSources())
)
);
}

@Override
public XML apply(final XML xmir) throws IOException {
return this.sheet.value().transform(xmir);
}
}
21 changes: 21 additions & 0 deletions src/main/resources/org/eolang/fixes/metas/unsorted-metas.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
* SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
* SPDX-License-Identifier: MIT
-->
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" id="unsorted-metas-fix" version="2.0">
<xsl:output encoding="UTF-8" method="xml"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="metas">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<xsl:apply-templates select="meta">
<xsl:sort select="concat(head, ' ', tail)"/>
</xsl:apply-templates>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
4 changes: 2 additions & 2 deletions src/main/resources/org/eolang/lints/metas/unsorted-metas.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
<xsl:for-each select="/object/metas/meta">
<xsl:variable name="meta-text" select="concat(head, ' ', tail)"/>
<xsl:variable name="previous" select="(preceding-sibling::meta)[1]"/>
<xsl:variable name="sibling-text" select="concat($previous/head/text(), ' ', $previous/tail/text())"/>
<xsl:if test="$meta-text &lt; $sibling-text">
<xsl:variable name="previous-text" select="concat($previous/head/text(), ' ', $previous/tail/text())"/>
<xsl:if test="$meta-text &lt; $previous-text">
<xsl:element name="defect">
<xsl:variable name="line" select="eo:lineno(@line)"/>
<xsl:attribute name="line">
Expand Down
63 changes: 63 additions & 0 deletions src/test/java/org/eolang/lints/FxUnsortedMetasTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
* SPDX-License-Identifier: MIT
*/
package org.eolang.lints;

import fixtures.EoProgram;
import java.util.Map;
import java.util.stream.Collectors;
import org.cactoos.io.InputOf;
import org.eolang.jucs.ClasspathSource;
import org.hamcrest.MatcherAssert;
import org.hamcrest.Matchers;
import org.junit.jupiter.params.ParameterizedTest;
import org.yaml.snakeyaml.Yaml;

/**
* Tests for {@link FxUnsortedMetas}.
* @since 0.2.1
* @todo #896:60min Replace partial meta comparison with exact XMIR match.
* Currently the test only compares the ordered sequence of "head tail"
* strings extracted from the metas section. Since we have a clear 'input'
* and 'output' EO program in each YAML pack, we should compare the full
* XMIR structure of the fixed result against the expected XMIR, ignoring
* only volatile attributes such as @line numbers.
*/
final class FxUnsortedMetasTest {

@ParameterizedTest
@ClasspathSource(value = "org/eolang/lints/fixes/unsorted-metas/", glob = "**.yaml")
void fixesUnsortedMetas(final String yaml) throws Exception {
final Map<String, Object> pack = new Yaml().load(yaml);
final Object input = pack.get("input");
final Object output = pack.get("output");
MatcherAssert.assertThat(
"Metas after fix must match the expected order",
new FxUnsortedMetas().apply(
new EoProgram(
String.valueOf(input.hashCode()),
new InputOf(input.toString())
).parse()
).nodes("/object/metas/meta").stream().map(
m -> String.format(
"%s %s",
m.xpath("head/text()").get(0),
m.xpath("tail/text()").get(0)
)
).collect(Collectors.toList()),
Matchers.equalTo(
new EoProgram(
String.valueOf(output.hashCode()),
new InputOf(output.toString())
).parse().nodes("/object/metas/meta").stream().map(
m -> String.format(
"%s %s",
m.xpath("head/text()").get(0),
m.xpath("tail/text()").get(0)
)
).collect(Collectors.toList())
)
);
}
}
3 changes: 2 additions & 1 deletion src/test/java/org/eolang/lints/LtByXslTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,15 @@ void checksLocationsOfYamlPacks() throws IOException {
@SuppressWarnings("StreamResourceLeak")
void catchesLostYamls() throws IOException {
MatcherAssert.assertThat(
"All YAML files must be in allowed locations (single or wpa packs)",
"All YAML files must be in allowed locations (single, wpa packs, or fixes)",
Files.walk(Paths.get("src/test/resources/org/eolang/lints"))
.filter(Files::isRegularFile)
.filter(LtByXslTest.yamls())
.map(path -> path.getParent().getParent().toString()).allMatch(
path ->
path.endsWith("org/eolang/lints/packs/single")
|| path.endsWith("org/eolang/lints/packs/wpa")
|| path.contains("org/eolang/lints/fixes")
),
Matchers.equalTo(true)
);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# SPDX-FileCopyrightText: Copyright (c) 2016-2026 Objectionary.com
# SPDX-License-Identifier: MIT
---
sheets:
- /org/eolang/fixes/metas/unsorted-metas.xsl
input: |
+version 0.0.0
+spdx SPDX-License-Identifier: MIT

# No comments.
[] > foo
42 > @
output: |
+spdx SPDX-License-Identifier: MIT
+version 0.0.0

# No comments.
[] > foo
42 > @
Loading