Skip to content

Commit

Permalink
Qute now support optional end tags for sections
Browse files Browse the repository at this point in the history
Fixes #879

Signed-off-by: azerr <azerr@redhat.com>
  • Loading branch information
angelozerr committed Jul 20, 2023
1 parent e9f7d94 commit c3e6655
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 10 deletions.
2 changes: 1 addition & 1 deletion qute.ls/com.redhat.qute.ls/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
<maven.build.timestamp.format>yyyyMMdd-HHmm</maven.build.timestamp.format>
<dev.build.timestamp>${maven.build.timestamp}</dev.build.timestamp>
<lsp4j.version>0.14.0</lsp4j.version>
<qute.version>2.15.3.Final</qute.version>
<qute.version>3.2.0.Final</qute.version>
<junit.version>5.6.1</junit.version>
<jboss.releases.repo.id>jboss-releases-repository</jboss.releases.repo.id>
<jboss.releases.repo.url>https://repository.jboss.org/nexus/content/repositories/releases/</jboss.releases.repo.url>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -238,16 +238,42 @@ public Section getOrphanEndSection(int offset, String tagName, boolean anyOrphan
return null;
}


/**
* Returns the parent section of the node and null otherwise.
*
* @return the parent section of the node and null otherwise.
*/
public Section getParentSection() {
return getParentSection(false);
}
/**
* Returns the parent section of the node and null otherwise.
*
* @return the parent section of the node and null otherwise.
*/
public Section getParentSection(boolean excludeSupportUnterminatedSection) {
Node parent = getParent();
while (parent != null && parent.getKind() != NodeKind.Template) {
if (parent != null && parent.getKind() == NodeKind.Section) {
return (Section) parent;
Section parentSection = (Section) parent;
if (!excludeSupportUnterminatedSection) {
// we don't exclude #let, #include which can be not closed
return parentSection;
}
if (parentSection.hasEndTag()) {
// {#for}foo{/for}
// here #for is the parent section of foo
return parentSection;
}
if (!parentSection.canSupportUnterminatedSection()) {
// {#for}foo
// here #for is the parent section of foo
// But
// {#let}foo
// here #let is NOT the parent section of foo
return parentSection;
}
}
parent = parent.getParent();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,7 @@ public boolean isSameTag(String tag) {

@Override
public Section getOrphanEndSection(int offset, String tagName, boolean anyOrphan) {
if ( getEnd() <= offset) {
if (getEnd() <= offset) {
// <employee />|
// <employee /> |
// <employee></employee> |
Expand All @@ -562,7 +562,8 @@ public Section getOrphanEndSection(int offset, String tagName, boolean anyOrphan
Section childSection = (Section) child;
if (childSection.isOrphanEndTagOf(tagName)) {
return childSection;
} else if (orphanEndSection == null && childSection.isOrphanEndTag()) {
} else if (orphanEndSection == null && childSection.isOrphanEndTag()
&& !childSection.canSupportUnterminatedSection()) {
orphanEndSection = childSection;
}
}
Expand Down Expand Up @@ -660,7 +661,7 @@ public List<SectionKind> getBlockLabels() {
}

public boolean isSectionBlock() {
Section parentSection = getParentSection();
Section parentSection = getParentSection(true);
return (parentSection != null && parentSection.getBlockLabels().contains(getSectionKind()));
}

Expand Down Expand Up @@ -760,4 +761,16 @@ public boolean hasEmptyEndTag() {
return getEndTagCloseOffset() - getEndTagOpenOffset() == 2;
}

/**
* Returns true if the section can support unterminated section (ex : #let or
* #include) and false otherwise.
*
* @param section the section.
*
* @return true if the section can support unterminated section (ex: #let or
* #include) and false otherwise.
*/
public boolean canSupportUnterminatedSection() {
return false;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,4 +113,8 @@ protected void accept0(ASTVisitor visitor) {
visitor.endVisit(this);
}

@Override
public boolean canSupportUnterminatedSection() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,9 @@ protected void accept0(ASTVisitor visitor) {
}
visitor.endVisit(this);
}

@Override
public boolean canSupportUnterminatedSection() {
return true;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,9 @@ protected void accept0(ASTVisitor visitor) {
}
visitor.endVisit(this);
}

@Override
public boolean canSupportUnterminatedSection() {
return super.canSupportUnterminatedSection();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import com.redhat.qute.parser.template.ASTVisitor;
import com.redhat.qute.parser.template.Section;
import com.redhat.qute.parser.template.SectionKind;
import com.redhat.qute.parser.template.sections.CaseSection;
import com.redhat.qute.parser.template.sections.CustomSection;
import com.redhat.qute.parser.template.sections.EachSection;
Expand Down Expand Up @@ -194,11 +195,14 @@ private void validateSectionSyntax(Section section) {
if (sectionBlock) {
// {#else} is valid if it is declared in an {#if}
} else {
// {#for}{#each}{/each}
// --> Parser error: unterminated section [for] detected
Range startSectionRange = QutePositionUtility.selectStartTagName(section);
reporter.reportError(startSectionRange, section, QuteSyntaxErrorCode.UNTERMINATED_SECTION,
section.getTag());
// #let and #include can be not closed
if (!section.canSupportUnterminatedSection()) {
// {#for}{#each}{/each}
// --> Parser error: unterminated section [for] detected
Range startSectionRange = QutePositionUtility.selectStartTagName(section);
reporter.reportError(startSectionRange, section, QuteSyntaxErrorCode.UNTERMINATED_SECTION,
section.getTag());
}
}
}
}
Expand All @@ -213,4 +217,5 @@ private void validateSectionSyntax(Section section) {
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import org.junit.jupiter.api.Test;

import com.redhat.qute.parser.validator.QuteSyntaxErrorCode;
import com.redhat.qute.services.diagnostics.QuteErrorCode;

/**
* Syntax error which improves the error of the real Qute parser.
Expand All @@ -31,6 +32,39 @@
*/
public class QuteDiagnosticsOverridedSyntaxErrorTest {

@Test
public void UNTERMINATED_SECTION_with_let() throws Exception {
String template = "{#let name='foo'}";
testDiagnosticsFor(template);
}

@Test
public void UNTERMINATED_SECTION_with_let_insideIf() throws Exception {
String template = "{#if true}\r\n" + //
" {#let sandwich='salami'}\r\n" + //
"{#else}\r\n" + //
"{/if}";
testDiagnosticsFor(template);
}

@Test
public void UNTERMINATED_SECTION_with_include() throws Exception {
String template = "{#include template}";
Diagnostic d = d(0, 10, 0, 18, QuteErrorCode.TemplateNotFound,
"Template not found: `template`.",
DiagnosticSeverity.Error);
testDiagnosticsFor(template, d);
}

@Test
public void UNTERMINATED_SECTION_with_insert() throws Exception {
String template = "{#insert}";
Diagnostic d = d(0, 1, 0, 8, QuteSyntaxErrorCode.UNTERMINATED_SECTION,
"Parser error: unterminated section [insert] detected",
DiagnosticSeverity.Error);
testDiagnosticsFor(template, d);
}

@Test
public void UNTERMINATED_SECTION() throws Exception {
String template = "{@java.util.List items}\r\n"
Expand Down

0 comments on commit c3e6655

Please sign in to comment.