Skip to content
Open
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
63 changes: 63 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,17 @@
<artifactId>jsr305</artifactId>
<version>3.0.2</version>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js</artifactId>
<version>22.2.0</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.graalvm.js</groupId>
<artifactId>js-scriptengine</artifactId>
<version>22.2.0</version>
</dependency>
<dependency>
<groupId>com.yegor256</groupId>
<artifactId>tojos</artifactId>
Expand Down Expand Up @@ -716,6 +727,29 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<!-- version from the parent pom -->
<executions>
<execution>
<id>copy-javascript</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/javascript</outputDirectory>
<resources>
<resource>
<directory>src/main/javascript</directory>
<filtering>false</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
Expand All @@ -740,6 +774,35 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>com.github.eirslett</groupId>
<artifactId>frontend-maven-plugin</artifactId>
<version>1.15.1</version>
<executions>
<execution>
<id>install-node-and-npm</id>
<goals>
<goal>install-node-and-npm</goal>
</goals>
<configuration>
<nodeVersion>v18.17.1</nodeVersion>
<npmVersion>9.8.1</npmVersion>
</configuration>
</execution>
<execution>
<id>npm-install</id>
<goals>
<goal>npm</goal>
</goals>
<phase>process-resources</phase>
<configuration>
<arguments>install</arguments>
<workingDirectory>${project.build.directory}/javascript</workingDirectory>
<installDirectory>.</installDirectory>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Change installDirectory to avoid polluting project root.

Setting installDirectory to . will install Node.js in the project root, which could lead to unwanted files in version control.

-              <installDirectory>.</installDirectory>
+              <installDirectory>${project.build.directory}</installDirectory>
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<installDirectory>.</installDirectory>
<installDirectory>${project.build.directory}</installDirectory>
🤖 Prompt for AI Agents
In pom.xml at line 734, the installDirectory is set to '.', which installs
Node.js in the project root and may clutter version control. Change the
installDirectory to a dedicated subdirectory (e.g., 'node' or 'target/node')
within the project to isolate installed files and avoid polluting the root
directory.

</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
15 changes: 15 additions & 0 deletions src/main/java/org/eolang/lints/Defect.java
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,21 @@ public Default(
this(rule, severity, object, line, text, false);
}

/**
* Ctor.
* @param rule Rule name
* @param severity Severity level
* @param line Line number
* @param text Description of the defect
* @checkstyle ParameterNumberCheck (5 lines)
*/
Default(
final String rule, final Severity severity,
final int line, final String text
) {
this(rule, severity, "", line, text);
}

/**
* Ctor.
* <p>
Expand Down
92 changes: 92 additions & 0 deletions src/main/java/org/eolang/lints/LtInvalidMarkdownComment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com
* SPDX-License-Identifier: MIT
*/
package org.eolang.lints;

import com.github.lombrozo.xnav.Xnav;
import com.jcabi.xml.XML;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.cactoos.io.ResourceOf;
import org.cactoos.text.IoCheckedText;
import org.cactoos.text.TextOf;
import org.eolang.parser.OnDefault;

/**
* Comments should not be violated from the point of view of markdownlint.
* This lint works for multiple files, as creating a MarkdownLinter takes a very long time
* and creating it many times is a bad idea.
*
* @since 0.0.47
*/
final class LtInvalidMarkdownComment implements Lint<Map<String, XML>> {
/**
* Markdownlint rule names to ignore.
*/
private static final Set<String> IGNORED = Set.of(
"MD041",
"MD047",
"MD026"
);

@Override
public String name() {
return "invalid-markdown-comment";
}

@Override
public Collection<Defect> defects(final Map<String, XML> pkg) throws IOException {
final Collection<Defect> defects = new ArrayList<>(0);
try (MarkdownLinter mdlinter = new MarkdownLinter()) {
for (final XML xmir : pkg.values()) {
this.defectsOfXmir(xmir, mdlinter).forEach(defects::add);
}
}
return defects;
}

@Override
public String motive() throws IOException {
return new IoCheckedText(
new TextOf(
new ResourceOf(
String.format(
"org/eolang/motives/comments/%s.md",
this.name()
)
)
)
).asString();
}

private Stream<Defect> defectsOfXmir(final XML xmir, final MarkdownLinter mdlinter) {
final Stream.Builder<Defect> defects = Stream.builder();
final List<Xnav> comments = new Xnav(xmir.inner()).path("/object/comments/comment")
.collect(Collectors.toList());
for (final Xnav comment : comments) {
final String text = comment.text().get().replace("\\n", "\n");
final int length = text.split("\n", -1).length;
final int line = Integer.parseInt(comment.attribute("line").text().orElse("0"));
mdlinter.defects(text)
.filter(defect -> !LtInvalidMarkdownComment.IGNORED.contains(defect.rule()))
.map(
defect -> new Defect.Default(
this.name(),
defect.severity(),
new OnDefault(xmir).get(),
line - 1 - length + defect.line(),
defect.text()
)
)
.forEach(defects::add);
}
return defects.build();
}
}
103 changes: 103 additions & 0 deletions src/main/java/org/eolang/lints/MarkdownLinter.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com
* SPDX-License-Identifier: MIT
*/
package org.eolang.lints;

import java.io.Closeable;
import java.util.stream.Stream;
import org.cactoos.io.ResourceOf;
import org.cactoos.io.UncheckedInput;
import org.cactoos.text.FormattedText;
import org.cactoos.text.TextOf;
import org.cactoos.text.UncheckedText;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;

/**
* Markdownlint interop. It can take a very long time to create.
*
* @since 0.0.47
*/
final class MarkdownLinter implements Closeable {
/**
* JavaScript code of markdownlint with function, that run markdownlint on single string.
*/
private static final String JSCODE = String.format(
"%s%s",
"globalThis.URL=class{constructor(input){this.href=input;}};",
new UncheckedText(
new TextOf(
new UncheckedInput(
new ResourceOf("markdownlint.js")
)
)
).asString()
);

/**
* JavaScripts context with markdownlint.
*/
private final Context context;

/**
* Function lint from JavaScript, that accept string and return rules violations.
*/
private final Value mdlint;

@SuppressWarnings("PMD.ConstructorOnlyInitializesOrCallOtherConstructors")
MarkdownLinter() {
this.context = Context.newBuilder("js")
.option("engine.WarnInterpreterOnly", "false")
.build();
this.context.eval("js", MarkdownLinter.JSCODE);
this.mdlint = this.context.getBindings("js").getMember("lint");
}

public Stream<Defect.Default> defects(final String text) {
final Stream.Builder<Defect.Default> defects = Stream.builder();
final Value errors = this.mdlint.execute(text);
for (int idx = 0; idx < errors.getArraySize(); idx += 1) {
final Value error = errors.getArrayElement(idx);
final String rule = rule(error.getMember("ruleNames"));
defects.add(
new Defect.Default(
rule,
Severity.WARNING,
error.getMember("lineNumber").asInt(),
new UncheckedText(
new FormattedText(
"[%s] %s. See %s",
rule,
error.getMember("ruleDescription").asString(),
error.getMember("ruleInformation").asString()
)
).asString()
)
);
}
return defects.build();
}

@Override
public void close() {
this.context.close();
}

/**
* MD rule.
*
* @param names Javascript array of names.
* @return The first name starting with MD.
* @throws IllegalStateException If no name starting with MD is found.
*/
private static String rule(final Value names) {
for (int idx = 0; idx < names.getArraySize(); idx += 1) {
final String name = names.getArrayElement(idx).asString();
if (name.startsWith("MD")) {
return name;
}
}
throw new IllegalStateException("cannot find name of markdown lint starting with MD");
}
}
3 changes: 2 additions & 1 deletion src/main/java/org/eolang/lints/WpaLints.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ final class WpaLints extends IterableEnvelope<Lint<Map<String, XML>>> {
new LtObjectIsNotUnique(),
new LtAtomIsNotUnique(),
new LtInconsistentArgs(),
new LtIncorrectNumberOfAttrs()
new LtIncorrectNumberOfAttrs(),
new LtInvalidMarkdownComment()
)
);
}
Expand Down
20 changes: 20 additions & 0 deletions src/main/javascript/markdownlint.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Marat-Tim let's add puzzle to integrate eslint into repository

* SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com
* SPDX-License-Identifier: MIT
*/
/**
* @todo #15:45min Add eslint to repository https://github.com/eslint/eslint.
* We should integrate eslint into repository to monitor the quality of code written in java script.
*/
import { lint as lintSync } from "markdownlint/sync";

globalThis.lint = function(text) {
const options = {
"strings": {
"file": text
}
};

const results = lintSync(options);
return results["file"];
}
15 changes: 15 additions & 0 deletions src/main/javascript/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"type": "module",
"name": "markdownlint",
"version": "1.0.0",
"main": "markdownlint.js",
"scripts": {
"postinstall": "npx webpack"
},
"dependencies": {
"markdownlint": "^0.37.4"
},
"devDependencies": {
"webpack-cli": "^6.0.1"
}
}
24 changes: 24 additions & 0 deletions src/main/javascript/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* SPDX-FileCopyrightText: Copyright (c) 2016-2025 Objectionary.com
* SPDX-License-Identifier: MIT
*/
import path from 'path';
import { fileURLToPath } from 'url';

export default {
entry: './markdownlint.js',
output: {
filename: '../classes/markdownlint.js',
path: path.dirname(fileURLToPath(import.meta.url)),
},
mode: 'production',
target: ['webworker'],
resolve: {
fallback: {
fs: false,
path: false,
os: false,
assert: false,
},
}
};
Loading
Loading