Skip to content

Commit

Permalink
Qute validation fails on {config:property} if property contains is a
Browse files Browse the repository at this point in the history
string

Fixes redhat-developer#933

Signed-off-by: azerr <[email protected]>
  • Loading branch information
angelozerr committed Nov 9, 2024
1 parent c3934d1 commit bec2cec
Show file tree
Hide file tree
Showing 3 changed files with 119 additions and 93 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
public class ExpressionScanner extends AbstractScanner<TokenType, ScannerState> {

private static final int[] QUOTE_OR_PAREN = new int[] { '(', ')', '"', '\'', };
private static final int[] SPACE_PERIOD_LBRACKET = new int[] {' ', '.', '['};
private static final int[] SPACE_PERIOD_LBRACKET_LPAREN_COLON = new int[] {' ', '.', '[', '(', ':'};
private static final int[] SPACE_PERIOD_LBRACKET = new int[] { ' ', '.', '[' };
private static final int[] SPACE_PERIOD_LBRACKET_LPAREN_COLON = new int[] { ' ', '.', '[', '(', ':' };

public static ExpressionScanner createScanner(String input, boolean canSupportInfixNotation) {
return createScanner(input, canSupportInfixNotation, 0, input.length());
Expand Down Expand Up @@ -62,97 +62,105 @@ protected TokenType internalScan() {
String errorMessage = null;
switch (state) {

case WithinExpression: {
if (stream.skipWhitespace()) {
return finishToken(offset, TokenType.Whitespace);
}
if (!canSupportInfixNotation) {
if (stream.advanceIfChar('"') || stream.advanceIfChar('\'')) {
state = ScannerState.WithinString;
return finishToken(stream.pos() - 1, TokenType.StartString);
case WithinExpression: {
if (stream.skipWhitespace()) {
return finishToken(offset, TokenType.Whitespace);
}
if (!canSupportInfixNotation) {
if (stream.advanceIfChar('"') || stream.advanceIfChar('\'')) {
state = ScannerState.WithinString;
return finishToken(stream.pos() - 1, TokenType.StartString);
}
}
nextJavaIdentifierPart();
return finishTokenPart(offset);
}
nextJavaIdentifierPart();
return finishTokenPart(offset);
}

case WithinParts:
case AfterNamespace: {
if (stream.skipWhitespace()) {
nbParts++;
return finishToken(offset, TokenType.Whitespace);
}
if (!canSupportInfixNotation) {
if (stream.advanceIfChar('"') || stream.advanceIfChar('\'')) {
state = ScannerState.WithinString;
return finishToken(stream.pos() - 1, TokenType.StartString);
case WithinParts:
case AfterNamespace: {
if (stream.skipWhitespace()) {
nbParts++;
return finishToken(offset, TokenType.Whitespace);
}
}
if (stream.advanceIfChar('.')) {
// item.|
return finishToken(offset, TokenType.Dot);
}
if (stream.advanceIfChar('[')) {
// item[|
if (stream.advanceUntilChar(']')) {
stream.advance(1);
// item['name']|
if (!canSupportInfixNotation) {
if (stream.advanceIfChar('"') || stream.advanceIfChar('\'')) {
state = ScannerState.WithinString;
return finishToken(stream.pos() - 1, TokenType.StartString);
}
}
return finishToken(offset, TokenType.PropertyPart);
}
if (stream.advanceIfChar(':')) {
// data:|
return finishToken(offset, TokenType.ColonSpace);
if (state == ScannerState.AfterNamespace) {
if (stream.peekChar() == '"' || stream.peekChar() == '\'') {
// config:"
stream.advance(1);
state = ScannerState.WithinString;
return finishToken(stream.pos() - 1, TokenType.StartString);
}
}
if (stream.advanceIfChar('.')) {
// item.|
return finishToken(offset, TokenType.Dot);
}
if (stream.advanceIfChar('[')) {
// item[|
if (stream.advanceUntilChar(']')) {
stream.advance(1);
// item['name']|
}
return finishToken(offset, TokenType.PropertyPart);
}
if (stream.advanceIfChar(':')) {
// data:|
return finishToken(offset, TokenType.ColonSpace);
}
nextJavaIdentifierPart();
// item.name|
return finishTokenPart(offset);
}
nextJavaIdentifierPart();
// item.name|
return finishTokenPart(offset);
}

case WithinMethod: {
if (stream.advanceIfChar('(')) {
bracket++;
return finishToken(offset, TokenType.OpenBracket);
}
stream.advanceUntilChar(QUOTE_OR_PAREN);
if (stream.peekChar() == '(') {
stream.advance(1);
bracket++;
return internalScan();
}
if (stream.peekChar() == '"' || stream.peekChar() == '\'') {
stream.advance(1);
state = ScannerState.WithinString;
inMethod = true;
return finishToken(stream.pos() - 1, TokenType.StartString);
} else if (stream.peekChar() == ')') {
stream.advance(1);
bracket--;
if (bracket > 0) {
case WithinMethod: {
if (stream.advanceIfChar('(')) {
bracket++;
return finishToken(offset, TokenType.OpenBracket);
}
stream.advanceUntilChar(QUOTE_OR_PAREN);
if (stream.peekChar() == '(') {
stream.advance(1);
bracket++;
return internalScan();
}
state = ScannerState.WithinParts;
inMethod = false;
return finishToken(stream.pos() - 1, TokenType.CloseBracket);
if (stream.peekChar() == '"' || stream.peekChar() == '\'') {
stream.advance(1);
state = ScannerState.WithinString;
inMethod = true;
return finishToken(stream.pos() - 1, TokenType.StartString);
} else if (stream.peekChar() == ')') {
stream.advance(1);
bracket--;
if (bracket > 0) {
return internalScan();
}
state = ScannerState.WithinParts;
inMethod = false;
return finishToken(stream.pos() - 1, TokenType.CloseBracket);
}
return internalScan();
}
return internalScan();
}

case WithinString: {
if (stream.advanceIfAnyOfChars(QUOTE_C)) {
if (inMethod) {
state = ScannerState.WithinMethod;
} else {
state = ScannerState.WithinExpression;
case WithinString: {
if (stream.advanceIfAnyOfChars(QUOTE_C)) {
if (inMethod) {
state = ScannerState.WithinMethod;
} else {
state = ScannerState.WithinExpression;
}
return finishToken(offset, TokenType.EndString);
}
return finishToken(offset, TokenType.EndString);
stream.advanceUntilChar(QUOTE);
return finishToken(offset, TokenType.String);
}
stream.advanceUntilChar(QUOTE);
return finishToken(offset, TokenType.String);
}

default:
inMethod = false;
default:
inMethod = false;
}
stream.advance(1);
return finishToken(offset, TokenType.Unknown, errorMessage);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ public void testObjectAndMethodPartWithParameters() {
assertOffsetAndToken(25, TokenType.CloseBracket, ")");
assertOffsetAndToken(26, TokenType.EOS, "");
}

@Test
public void testNamespaceStartWithObject() {
scanner = createInfixNotationScanner("data:foo");
Expand Down Expand Up @@ -127,6 +127,17 @@ public void testNamespaceWithMethodAndProperty() {
assertOffsetAndToken(18, TokenType.EOS, "");
}

@Test
public void configNamespaceWithString() {
scanner = createInfixNotationScanner("config:\"quarkus.application.name\"");
assertOffsetAndToken(0, TokenType.NamespacePart, "config");
assertOffsetAndToken(6, TokenType.ColonSpace, ":");
assertOffsetAndToken(7, TokenType.StartString, "\"");
assertOffsetAndToken(8, TokenType.String, "quarkus.application.name");
assertOffsetAndToken(32, TokenType.EndString, "\"");
assertOffsetAndToken(33, TokenType.EOS, "");
}

/**
* @see https://quarkus.io/guides/qute-reference#built-in-resolvers
*/
Expand Down Expand Up @@ -155,7 +166,7 @@ public void underscore() {
}

// Infix notation tests

@Test
public void testTwoPartsWithInfixNotation() {
scanner = createInfixNotationScanner("a b");
Expand All @@ -173,7 +184,7 @@ public void testTwoPartsWithoutInfixNotation() {
assertOffsetAndToken(2, TokenType.ObjectPart, "b"); // No infix notation -> object part
assertOffsetAndToken(3, TokenType.EOS, "");
}

@Test
public void testThreePartsWithInfixNotation() {
scanner = createInfixNotationScanner("a b c");
Expand All @@ -184,7 +195,7 @@ public void testThreePartsWithInfixNotation() {
assertOffsetAndToken(4, TokenType.InfixParameter, "c");
assertOffsetAndToken(5, TokenType.EOS, "");
}

@Test
public void testSeveralPartsWithInfixNotation() {
scanner = createInfixNotationScanner("a b c d e");
Expand All @@ -199,7 +210,7 @@ public void testSeveralPartsWithInfixNotation() {
assertOffsetAndToken(8, TokenType.InfixParameter, "e");
assertOffsetAndToken(9, TokenType.EOS, "");
}

@Test
public void testThreePartsWithoutInfixNotation() {
scanner = createNoInfixNotationScanner("a b c");
Expand All @@ -210,7 +221,7 @@ public void testThreePartsWithoutInfixNotation() {
assertOffsetAndToken(4, TokenType.ObjectPart, "c");
assertOffsetAndToken(5, TokenType.EOS, "");
}

@Test
public void testOrInfixNotation() {
scanner = createInfixNotationScanner("person.name or 'John'");
Expand All @@ -223,7 +234,7 @@ public void testOrInfixNotation() {
assertOffsetAndToken(15, TokenType.InfixParameter, "'John'");
assertOffsetAndToken(21, TokenType.EOS, "");
}

@Test
public void testCharAtInfixNotation() {
scanner = createInfixNotationScanner("foo charAt '1'");
Expand All @@ -234,7 +245,7 @@ public void testCharAtInfixNotation() {
assertOffsetAndToken(11, TokenType.InfixParameter, "'1'");
assertOffsetAndToken(14, TokenType.EOS, "");
}

@Test
public void testCharAtNoInfixNotation() {
scanner = createNoInfixNotationScanner("foo charAt '1'");
Expand All @@ -247,7 +258,7 @@ public void testCharAtNoInfixNotation() {
assertOffsetAndToken(13, TokenType.EndString, "'");
assertOffsetAndToken(14, TokenType.EOS, "");
}

@Test
public void testMethodsAndInfixNotation() {
scanner = createInfixNotationScanner("items.get(0) or 1");
Expand All @@ -262,7 +273,7 @@ public void testMethodsAndInfixNotation() {
assertOffsetAndToken(16, TokenType.InfixParameter, "1");
assertOffsetAndToken(17, TokenType.EOS, "");
}

@Test
public void dotSpace() {
scanner = createInfixNotationScanner("items. ");
Expand All @@ -271,7 +282,7 @@ public void dotSpace() {
assertOffsetAndToken(6, TokenType.Whitespace, " ");
assertOffsetAndToken(7, TokenType.EOS, "");
}

@Test
public void twoMethodsWithOr() {
scanner = createInfixNotationScanner("item.name or item.name");
Expand All @@ -284,7 +295,7 @@ public void twoMethodsWithOr() {
assertOffsetAndToken(13, TokenType.InfixParameter, "item.name");
assertOffsetAndToken(22, TokenType.EOS, "");
}

@Test
public void infixNotationWithBracket() {
scanner = createInfixNotationScanner("foo getBytes()");
Expand All @@ -304,7 +315,7 @@ public void elvisOperator() {
assertOffsetAndToken(8, TokenType.InfixParameter, "\"Quarkus Insights\"");
assertOffsetAndToken(26, TokenType.EOS, "");
}

private void assertOffsetAndToken(int tokenOffset, TokenType tokenType, String tokenText) {
TokenType token = scanner.scan();
assertEquals(tokenOffset, scanner.getTokenOffset());
Expand All @@ -315,7 +326,7 @@ private void assertOffsetAndToken(int tokenOffset, TokenType tokenType, String t
private ExpressionScanner createInfixNotationScanner(String input) {
return ExpressionScanner.createScanner(input, true);
}

private ExpressionScanner createNoInfixNotationScanner(String input) {
return ExpressionScanner.createScanner(input, false);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -690,4 +690,11 @@ public void escape() throws Exception {
String template = "function gtag()\\{dataLayer.push(arguments);\\}";
testDiagnosticsFor(template);
}

@Test
public void configNamepscaeWithString() throws Exception {
String template = "{config:\"quarkus.application.name\"}";
testDiagnosticsFor(template);
}

}

0 comments on commit bec2cec

Please sign in to comment.