Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Include dir support for diagnostics #238

Merged
merged 13 commits into from
Dec 5, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@

import io.openliberty.tools.langserver.lemminx.codeactions.AddAttribute;
import io.openliberty.tools.langserver.lemminx.codeactions.AddFeature;
import io.openliberty.tools.langserver.lemminx.codeactions.AddTrailingSlash;
import io.openliberty.tools.langserver.lemminx.codeactions.CreateFile;
import io.openliberty.tools.langserver.lemminx.codeactions.EditAttribute;
import io.openliberty.tools.langserver.lemminx.codeactions.RemoveTrailingSlash;
import io.openliberty.tools.langserver.lemminx.codeactions.ReplaceFeature;

public class LibertyCodeActionParticipant implements ICodeActionParticipant {
Expand Down Expand Up @@ -57,6 +59,8 @@ private void registerCodeActions() {
codeActionParticipants.put(LibertyDiagnosticParticipant.IMPLICIT_NOT_OPTIONAL_CODE, new AddAttribute());
codeActionParticipants.put(LibertyDiagnosticParticipant.INCORRECT_FEATURE_CODE, new ReplaceFeature());
codeActionParticipants.put(LibertyDiagnosticParticipant.MISSING_CONFIGURED_FEATURE_CODE, new AddFeature());
codeActionParticipants.put(LibertyDiagnosticParticipant.IS_FILE_NOT_DIR_CODE, new RemoveTrailingSlash());
codeActionParticipants.put(LibertyDiagnosticParticipant.Is_DIR_NOT_FILE_CODE, new AddTrailingSlash());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ public class LibertyDiagnosticParticipant implements IDiagnosticsParticipant {
public static final String IMPLICIT_NOT_OPTIONAL_MESSAGE = "The specified resource cannot be skipped. Check location value or add optional attribute.";
public static final String IMPLICIT_NOT_OPTIONAL_CODE = "implicit_not_optional";

public static final String SPECIFIED_DIR_IS_FILE = "Path specified a directory, but resource exists as a file. Please remove the trailing slash.";
public static final String SPECIFIED_FILE_IS_DIR = "Path specified a file, but resource exists as a directory. Please add a trailing slash.";
evie-lau marked this conversation as resolved.
Show resolved Hide resolved
public static final String IS_FILE_NOT_DIR_CODE = "is_file_not_dir";
public static final String Is_DIR_NOT_FILE_CODE = "is_dir_not_file";

public static final String INCORRECT_FEATURE_CODE = "incorrect_feature";

private Set<String> includedFeatures;
Expand Down Expand Up @@ -150,11 +155,14 @@ private void validateIncludeLocation(DOMDocument domDocument, List<Diagnostic> d
if (locAttribute.startsWith("http") || locAttribute.contains("$")) {
return;
}
// Liberty uses this to determine if directory.
boolean isLibertyDirectory = locAttribute.endsWith("/") || locAttribute.endsWith(File.separator);

DOMNode locNode = node.getAttributeNode("location");
Range range = XMLPositionUtility.createRange(locNode.getStart(), locNode.getEnd(), domDocument);
if (!locAttribute.endsWith(".xml")) {
String message = "The specified resource is not an XML file.";
if (!locAttribute.endsWith(".xml")
&& !isLibertyDirectory) {
String message = "The specified resource is not an XML file. If it is a directory, it must end with a trailing slash.";
evie-lau marked this conversation as resolved.
Show resolved Hide resolved
evie-lau marked this conversation as resolved.
Show resolved Hide resolved
diagnosticsList.add(new Diagnostic(range, message, DiagnosticSeverity.Warning, LIBERTY_LEMMINX_SOURCE));
return;
}
Expand All @@ -175,11 +183,28 @@ private void validateIncludeLocation(DOMDocument domDocument, List<Diagnostic> d
}
diagnosticsList.add(new Diagnostic(range, MISSING_FILE_MESSAGE, DiagnosticSeverity.Warning, LIBERTY_LEMMINX_SOURCE, MISSING_FILE_CODE));
}
validateFileOrDirIncludeLocation(configFile, isLibertyDirectory, range, diagnosticsList);
} catch (IllegalArgumentException e) {
diagnosticsList.add(new Diagnostic(range, MISSING_FILE_MESSAGE, DiagnosticSeverity.Warning, "liberty-lemminx-exception", MISSING_FILE_CODE));
}
}

/**
* Checks if specified file or dir is the correct filetype.
* Adds diagnostics if it is mismatched.
* @param f - <include> location file
* @param isLibertyDirectory - whether Liberty considers this specified as a dir (path ends in slash)
* @param range - Range to apply diagnostic message
* @param diagnosticsList
*/
private void validateFileOrDirIncludeLocation(File f, boolean isLibertyDirectory, Range range, List<Diagnostic> diagnosticsList) {
if (f.isFile() && isLibertyDirectory) {
cherylking marked this conversation as resolved.
Show resolved Hide resolved
diagnosticsList.add(new Diagnostic(range, SPECIFIED_DIR_IS_FILE, DiagnosticSeverity.Error, LIBERTY_LEMMINX_SOURCE, IS_FILE_NOT_DIR_CODE));
} else if (f.isDirectory() && !isLibertyDirectory) {
diagnosticsList.add(new Diagnostic(range, SPECIFIED_FILE_IS_DIR, DiagnosticSeverity.Error, LIBERTY_LEMMINX_SOURCE, Is_DIR_NOT_FILE_CODE));
}
}

/**
* Create temporary diagnostics for validation for single pass-through.
* @param domDocument
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
import org.eclipse.lsp4j.DocumentLink;
import org.eclipse.lsp4j.Range;

import io.openliberty.tools.langserver.lemminx.util.LibertyConstants;
import io.openliberty.tools.langserver.lemminx.util.LibertyUtils;


public class LibertyDocumentLinkParticipant implements IDocumentLinkParticipant {

private static final Logger LOGGER = Logger.getLogger(LibertyDocumentLinkParticipant.class.getName());
Expand All @@ -43,7 +43,7 @@ public void findDocumentLinks(DOMDocument document, List<DocumentLink> links) {
List<DOMNode> nodes = document.getDocumentElement().getChildren();

// collect all <include> nodes that are children of the document element
List<DOMNode> includeDomNodes = nodes.stream().filter(n -> ((n.getNodeName() != null) && n.getNodeName().equals("include")))
List<DOMNode> includeDomNodes = nodes.stream().filter(n -> ((n.getNodeName() != null) && n.getNodeName().equals(LibertyConstants.INCLUDE_ELEMENT)))
.collect(Collectors.toList());

for (DOMNode includeNode : includeDomNodes) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package io.openliberty.tools.langserver.lemminx.codeactions;
evie-lau marked this conversation as resolved.
Show resolved Hide resolved

import java.io.File;
import java.util.List;

import org.eclipse.lemminx.commons.CodeActionFactory;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.services.extensions.codeaction.ICodeActionParticipant;
import org.eclipse.lemminx.services.extensions.codeaction.ICodeActionRequest;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;

public class AddTrailingSlash implements ICodeActionParticipant {

@Override
public void doCodeAction(ICodeActionRequest request, List<CodeAction> codeActions, CancelChecker cancelChecker) {
Diagnostic diagnostic = request.getDiagnostic();
DOMDocument document = request.getDocument();
try {
String fileSeparator = "/";
evie-lau marked this conversation as resolved.
Show resolved Hide resolved
String locationText = document.findNodeAt(document.offsetAt(diagnostic.getRange().getEnd())).getAttribute("location");
if (locationText.contains("\\") && locationText.contains("/")) {
// if using mismatched slashes, replace all with /
locationText = locationText.replace("\\", "/");
} else if (File.separator.equals("\\") && locationText.contains("\\")) {
// if Windows and path using \, continue using it
fileSeparator = "\\";
}
String title = "Add trailing slash to specify directory.";
evie-lau marked this conversation as resolved.
Show resolved Hide resolved
String replaceText = "location=\"" + locationText + fileSeparator + "\"";
codeActions.add(CodeActionFactory.replace(title, diagnostic.getRange(), replaceText, document.getTextDocument(), diagnostic));
} catch (Exception e) {
// do nothing
cherylking marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package io.openliberty.tools.langserver.lemminx.codeactions;
evie-lau marked this conversation as resolved.
Show resolved Hide resolved

import java.util.List;

import org.eclipse.lemminx.commons.CodeActionFactory;
import org.eclipse.lemminx.dom.DOMDocument;
import org.eclipse.lemminx.services.extensions.codeaction.ICodeActionParticipant;
import org.eclipse.lemminx.services.extensions.codeaction.ICodeActionRequest;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;

public class RemoveTrailingSlash implements ICodeActionParticipant {

@Override
public void doCodeAction(ICodeActionRequest request, List<CodeAction> codeActions, CancelChecker cancelChecker) {
Diagnostic diagnostic = request.getDiagnostic();
DOMDocument document = request.getDocument();
try {
String locationText = document.findNodeAt(document.offsetAt(diagnostic.getRange().getEnd())).getAttribute("location");
String title = "Remove trailing slash to specify file.";
evie-lau marked this conversation as resolved.
Show resolved Hide resolved
String replaceText = "location=\"" + locationText.substring(0, locationText.length()-1) + "\"";
codeActions.add(CodeActionFactory.replace(title, diagnostic.getRange(), replaceText, document.getTextDocument(), diagnostic));
} catch (Exception e) {
// do nothing
cherylking marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,8 @@ public void testDiagnosticsForInclude() throws IOException {
" optional=\"true\" location=\"MULTI LINER\"/>", //
" <include optional=\"false\" location=\"MISSING FILE.xml\"/>", //
" <include location=\"MISSING FILE.xml\"/>", //
" <include location=\"/empty_server.xml/\"/>", //
" <include location=\"/testDir.xml\"/>", //
"</server>"
);

Expand All @@ -169,11 +171,11 @@ public void testDiagnosticsForInclude() throws IOException {

Diagnostic not_xml = new Diagnostic();
not_xml.setRange(r(3, 29, 3, 52));
not_xml.setMessage("The specified resource is not an XML file.");
not_xml.setMessage("The specified resource is not an XML file. If it is a directory, it must end with a trailing slash.");

Diagnostic multi_liner = new Diagnostic();
multi_liner.setRange(r(5, 28, 5, 50));
multi_liner.setMessage("The specified resource is not an XML file.");
multi_liner.setMessage("The specified resource is not an XML file. If it is a directory, it must end with a trailing slash.");

Diagnostic not_optional = new Diagnostic();
not_optional.setRange(r(6, 13, 6, 29));
Expand All @@ -195,9 +197,20 @@ public void testDiagnosticsForInclude() throws IOException {
missing_xml2.setCode("missing_file");
missing_xml2.setMessage("The resource at the specified location could not be found.");

// test dir not file? might be hard to test...
Diagnostic dirIsFile = new Diagnostic();
dirIsFile.setRange(r(8, 13, 8, 42));
dirIsFile.setCode("is_file_not_dir");
dirIsFile.setMessage("Path specified a directory, but resource exists as a file. Please remove the trailing slash.");

Diagnostic fileIsDir = new Diagnostic();
fileIsDir.setRange(r(9, 13, 9, 36));
fileIsDir.setCode("is_dir_not_file");
fileIsDir.setMessage("Path specified a file, but resource exists as a directory. Please add a trailing slash.");

XMLAssert.testDiagnosticsFor(serverXML, null, null, serverXMLFile.toURI().toString(),
not_xml, multi_liner, not_optional, missing_xml, optional_not_defined, missing_xml2);
not_xml, multi_liner, not_optional, missing_xml, optional_not_defined, missing_xml2,
dirIsFile, fileIsDir);
}

@Test
Expand Down
Empty file.