diff --git a/grammars/apex.tmLanguage b/grammars/apex.tmLanguage
index a9d52cc..62891de 100644
--- a/grammars/apex.tmLanguage
+++ b/grammars/apex.tmLanguage
@@ -3798,7 +3798,7 @@
conditional-operator
begin
- (?<!\?)\?(?!\?|\.|\[)
+ (?<!\?)\?(?!\?|\.(?!\d)|\[)
beginCaptures
0
diff --git a/grammars/apex.tmLanguage.cson b/grammars/apex.tmLanguage.cson
index 4accb9c..c32ff83 100644
--- a/grammars/apex.tmLanguage.cson
+++ b/grammars/apex.tmLanguage.cson
@@ -2242,7 +2242,7 @@ repository:
}
]
'conditional-operator':
- begin: '(?conditional-operator
begin
- (?<!\?)\?(?!\?|\.|\[)
+ (?<!\?)\?(?!\?|\.(?!\d)|\[)
beginCaptures
0
diff --git a/package.json b/package.json
index 8535766..2920533 100644
--- a/package.json
+++ b/package.json
@@ -39,7 +39,7 @@
"watch": "tsc -w -p .",
"test:soql-tmgrammar": "vscode-tmgrammar-test -g \"./grammars/soql.tmLanguage\" \"./test/soql/*.soql\" ",
"test:soql-tmgrammar-snapshots": "vscode-tmgrammar-snap -s source.soql -g \"./grammars/soql.tmLanguage\" \"./test/soql/snapshots/*.soql\" ",
- "test": "npm run compile && mocha out/test/**/*.tests.js && npm run test:soql-tmgrammar && npm run test:soql-tmgrammar-snapshots",
+ "test": "npm run compile && mocha out/test/**/*.test.js && npm run test:soql-tmgrammar && npm run test:soql-tmgrammar-snapshots",
"prepare": "npm run build",
"format": "prettier --config .prettierrc.json --write './**/*.{ts,js,json,md}'"
},
@@ -72,4 +72,4 @@
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
-}
+}
\ No newline at end of file
diff --git a/src/apex.tmLanguage.yml b/src/apex.tmLanguage.yml
index 5915856..3fe8b27 100644
--- a/src/apex.tmLanguage.yml
+++ b/src/apex.tmLanguage.yml
@@ -1342,7 +1342,8 @@ repository:
# Only match ? if:
# 1. There isn't a preceding or trailing ? (null-coalescing operator)
# 2. There isn't a trailing . or [ (null-conditional operator)
- begin: (? {
+ const input = Input.InMethod(`Decimal d = b?.34:0;`);
+ const tokens = await tokenize(input);
+
+ tokens.should.deep.equal([
+ Token.PrimitiveType.Decimal,
+ Token.Identifiers.LocalName('d'),
+ Token.Operators.Assignment,
+ Token.Variables.ReadWrite('b'),
+ Token.Operators.Conditional.QuestionMark,
+ Token.Literals.Numeric.Decimal('34'),
+ Token.Operators.Conditional.Colon,
+ Token.Literals.Numeric.Decimal('0'),
+ Token.Punctuation.Semicolon,
+ ]);
+ });
+
+ it('ternary with decimal literal with leading digits (W-8095488)', async () => {
+ const input = Input.InMethod(`Decimal i = b?.123:0;`);
+ const tokens = await tokenize(input);
+
+ tokens.should.deep.equal([
+ Token.PrimitiveType.Decimal,
+ Token.Identifiers.LocalName('i'),
+ Token.Operators.Assignment,
+ Token.Variables.ReadWrite('b'),
+ Token.Operators.Conditional.QuestionMark,
+ Token.Literals.Numeric.Decimal('123'),
+ Token.Operators.Conditional.Colon,
+ Token.Literals.Numeric.Decimal('0'),
+ Token.Punctuation.Semicolon,
+ ]);
+ });
+
+ it('ternary with decimal literal with spaces (W-8095488)', async () => {
+ const input = Input.InMethod(`Decimal d = b ? .34 : 0;`);
+ const tokens = await tokenize(input);
+
+ tokens.should.deep.equal([
+ Token.PrimitiveType.Decimal,
+ Token.Identifiers.LocalName('d'),
+ Token.Operators.Assignment,
+ Token.Variables.ReadWrite('b'),
+ Token.Operators.Conditional.QuestionMark,
+ Token.Literals.Numeric.Decimal('34'),
+ Token.Operators.Conditional.Colon,
+ Token.Literals.Numeric.Decimal('0'),
+ Token.Punctuation.Semicolon,
+ ]);
+ });
});
describe('Element Access', () => {
diff --git a/test/field.tests.ts b/test/field.test.ts
similarity index 100%
rename from test/field.tests.ts
rename to test/field.test.ts
diff --git a/test/for-statements.tests.ts b/test/for-statements.test.ts
similarity index 100%
rename from test/for-statements.tests.ts
rename to test/for-statements.test.ts
diff --git a/test/incomplete-code.tests.ts b/test/incomplete-code.test.ts
similarity index 100%
rename from test/incomplete-code.tests.ts
rename to test/incomplete-code.test.ts
diff --git a/test/initializer-block.tests.ts b/test/initializer-block.test.ts
similarity index 100%
rename from test/initializer-block.tests.ts
rename to test/initializer-block.test.ts
diff --git a/test/interface.tests.ts b/test/interface.test.ts
similarity index 100%
rename from test/interface.tests.ts
rename to test/interface.test.ts
diff --git a/test/javadoc.tests.ts b/test/javadoc.test.ts
similarity index 100%
rename from test/javadoc.tests.ts
rename to test/javadoc.test.ts
diff --git a/test/literals.tests.ts b/test/literals.test.ts
similarity index 100%
rename from test/literals.tests.ts
rename to test/literals.test.ts
diff --git a/test/local.tests.ts b/test/local.test.ts
similarity index 100%
rename from test/local.tests.ts
rename to test/local.test.ts
diff --git a/test/method.tests.ts b/test/method.test.ts
similarity index 100%
rename from test/method.tests.ts
rename to test/method.test.ts
diff --git a/test/operator.tests.ts b/test/operator.test.ts
similarity index 100%
rename from test/operator.tests.ts
rename to test/operator.test.ts
diff --git a/test/property.tests.ts b/test/property.test.ts
similarity index 100%
rename from test/property.tests.ts
rename to test/property.test.ts
diff --git a/test/queries.tests.ts b/test/queries.test.ts
similarity index 100%
rename from test/queries.tests.ts
rename to test/queries.test.ts
diff --git a/test/repros/force-app/main/default/classes/TernaryWithDecimals_W8095488.cls b/test/repros/force-app/main/default/classes/TernaryWithDecimals_W8095488.cls
new file mode 100644
index 0000000..f0d6503
--- /dev/null
+++ b/test/repros/force-app/main/default/classes/TernaryWithDecimals_W8095488.cls
@@ -0,0 +1,88 @@
+/**
+ * W-8095488: Ternary expression with decimals syntax highlighting
+ *
+ * When a ternary expression contains a decimal literal and spaces are excluded,
+ * the question mark may be incorrectly tokenized as a safe navigation operator
+ * instead of a ternary operator.
+ */
+public class TernaryWithDecimals_W8095488 {
+
+ // With spaces - should work correctly
+ public void ternaryWithSpaces() {
+ Boolean b = true;
+ Decimal d = b ? .34 : 0;
+ Decimal i = b?.123 : 0;
+ }
+
+ // Without spaces - potential tokenization issue
+ public void ternaryWithoutSpaces() {
+ Boolean b = true;
+ Decimal d = b?.34:0;
+ Decimal i = b?.123:0;
+ }
+
+ // Mixed scenarios
+ public void mixedScenarios() {
+ Boolean b = true;
+
+ // Space before question mark, no space after
+ Decimal d1 = b ?.34:0;
+
+ // No space before, space after
+ Decimal d2 = b? .34:0;
+
+ // Space after question mark, no space around colon
+ Decimal d3 = b? .34:0;
+
+ // All spaces
+ Decimal d4 = b ? .34 : 0;
+
+ // Integer values (for comparison)
+ Integer i1 = b?1:0;
+ Integer i2 = b ? 1 : 0;
+ }
+
+ // Safe navigation operator (for comparison)
+ public void safeNavigationOperator() {
+ String s = 'test';
+ Integer len = s?.length();
+
+ Account acc;
+ String name = acc?.Name;
+ }
+
+ // Complex expressions
+ public void complexExpressions() {
+ Boolean b = true;
+
+ // Ternary in switch
+ switch on (b) {
+ when true {
+ Decimal d = b?.34:0;
+ String s = 'SUCCESS';
+ }
+ }
+
+ // Nested ternary with decimals
+ Decimal nested = b ? (b?.5:.25) : .0;
+
+ // Ternary with decimal in variable declaration
+ Decimal inline = b?.99:0;
+ }
+
+ // Property access vs ternary
+ public void propertyVsTernary() {
+ Boolean b = true;
+
+ // These should be ternary operators, not safe navigation
+ Decimal d = b?.34:0;
+ Decimal i = b?.123:0;
+
+ // This is safe navigation
+ String type = this?.type;
+ }
+
+ String type = 'test';
+}
+
+
diff --git a/test/repros/force-app/main/default/classes/TernaryWithDecimals_W8095488.cls-meta.xml b/test/repros/force-app/main/default/classes/TernaryWithDecimals_W8095488.cls-meta.xml
new file mode 100644
index 0000000..259683a
--- /dev/null
+++ b/test/repros/force-app/main/default/classes/TernaryWithDecimals_W8095488.cls-meta.xml
@@ -0,0 +1,6 @@
+
+
+ 58.0
+ Active
+
+
diff --git a/test/statements.tests.ts b/test/statements.test.ts
similarity index 100%
rename from test/statements.tests.ts
rename to test/statements.test.ts
diff --git a/test/switch.tests.ts b/test/switch.test.ts
similarity index 100%
rename from test/switch.tests.ts
rename to test/switch.test.ts
diff --git a/test/system.tests.ts b/test/system.test.ts
similarity index 100%
rename from test/system.tests.ts
rename to test/system.test.ts
diff --git a/test/trigger.tests.ts b/test/trigger.test.ts
similarity index 100%
rename from test/trigger.tests.ts
rename to test/trigger.test.ts
diff --git a/test/type-name.tests.ts b/test/type-name.test.ts
similarity index 100%
rename from test/type-name.tests.ts
rename to test/type-name.test.ts
diff --git a/test/xml-doc-comment.tests.ts b/test/xml-doc-comment.test.ts
similarity index 100%
rename from test/xml-doc-comment.tests.ts
rename to test/xml-doc-comment.test.ts