diff --git a/changelog_unreleased/handlebars/16358.md b/changelog_unreleased/handlebars/16358.md
new file mode 100644
index 000000000..39f91fd2c
--- /dev/null
+++ b/changelog_unreleased/handlebars/16358.md
@@ -0,0 +1,13 @@
+#### Fix handlebars path expressions starts with `@` (#16358 by @Princeyadav05)
+
+
+```hbs
+{{! Input }}
+
{{@x.y.z}}
+
+{{! Prettier stable }}
+{{@x}}
+
+{{! Prettier main }}
+{{@x.y.z}}
+```
diff --git a/src/language-handlebars/clean.js b/src/language-handlebars/clean.js
index 04ac8aa60..cbf58e77f 100644
--- a/src/language-handlebars/clean.js
+++ b/src/language-handlebars/clean.js
@@ -32,6 +32,10 @@ function clean(original, cloned /*, parent*/) {
if (original.type === "AttrNode" && original.name.toLowerCase() === "class") {
delete cloned.value;
}
+
+ if (original.type === "PathExpression") {
+ cloned.head = original.head.original;
+ }
}
clean.ignoredProperties = new Set(["loc", "selfClosing"]);
diff --git a/src/language-handlebars/printer-glimmer.js b/src/language-handlebars/printer-glimmer.js
index ff1fdb2eb..53a4f2b99 100644
--- a/src/language-handlebars/printer-glimmer.js
+++ b/src/language-handlebars/printer-glimmer.js
@@ -366,10 +366,7 @@ function print(path, options, print) {
];
}
case "PathExpression":
- return printPathExpression(node, print);
-
- case "AtHead":
- return node.name;
+ return printPathExpression(node);
case "BooleanLiteral":
return String(node.value);
@@ -389,6 +386,7 @@ function print(path, options, print) {
case "NullLiteral":
return "null";
+ case "AtHead": // Handled in `printPathExpression`
case "VarHead": // Handled in `printPathExpression`
case "ThisHead": // Handled in `printPathExpression`
default:
@@ -784,21 +782,23 @@ const PATH_EXPRESSION_FORBIDDEN_IN_FIRST_PART = new Set([
"null",
"undefined",
]);
-const isPathExpressionPartNeedBrackets = (part, index) =>
- (index !== 0 && PATH_EXPRESSION_FORBIDDEN_IN_FIRST_PART.has(part)) ||
- /\s/.test(part) ||
- /^\d/.test(part) ||
- Array.prototype.some.call(part, (character) =>
- PATH_EXPRESSION_FORBIDDEN_CHARACTERS.has(character),
- );
-function printPathExpression(node, print) {
- if (node.head.type === "AtHead") {
- return print("head");
+const isPathExpressionPartNeedBrackets = (part, index) => {
+ if (index === 0 && part.startsWith("@")) {
+ return false;
}
+ return (
+ (index !== 0 && PATH_EXPRESSION_FORBIDDEN_IN_FIRST_PART.has(part)) ||
+ /\s/.test(part) ||
+ /^\d/.test(part) ||
+ Array.prototype.some.call(part, (character) =>
+ PATH_EXPRESSION_FORBIDDEN_CHARACTERS.has(character),
+ )
+ );
+};
+function printPathExpression(node) {
+ // check if node is a legacy path expression and leave it alone
if (node.tail.length === 0 && node.original.includes("/")) {
- // check if node has data, or
- // check if node is a legacy path expression (and leave it alone)
return node.original;
}
diff --git a/src/language-handlebars/visitor-keys.evaluate.js b/src/language-handlebars/visitor-keys.evaluate.js
index 4d2df7bf0..0c86c8e91 100644
--- a/src/language-handlebars/visitor-keys.evaluate.js
+++ b/src/language-handlebars/visitor-keys.evaluate.js
@@ -1,11 +1 @@
-import { visitorKeys as glimmerVisitorKeys } from "@glimmer/syntax";
-
-const visitorKeys = {
- VarHead: [],
- ThisHead: [],
- AtHead: [],
- ...glimmerVisitorKeys,
- PathExpression: [...glimmerVisitorKeys.PathExpression, "head"],
-};
-
-export default visitorKeys;
+export { visitorKeys as default } from "@glimmer/syntax";
diff --git a/tests/format/handlebars/path-expressions/__snapshots__/format.test.js.snap b/tests/format/handlebars/path-expressions/__snapshots__/format.test.js.snap
index 1e2af028a..0efe291d4 100644
--- a/tests/format/handlebars/path-expressions/__snapshots__/format.test.js.snap
+++ b/tests/format/handlebars/path-expressions/__snapshots__/format.test.js.snap
@@ -42,6 +42,10 @@ printWidth: 80
{{array.2.[@#].[1]}}
{{array.2.[a b]}}
{{this.test}}
+ {{@x.y.z}}
+ {{@array.[true]}}
+ {{@array.2.[@#].[1]}}
+ {{@array.2.[a b]}}
{{#if @foo}}
{{/if}}
@@ -54,6 +58,10 @@ printWidth: 80
{{array.[2].[@#].[1]}}
{{array.[2].[a b]}}
{{this.test}}
+ {{@x.y.z}}
+ {{@array.[true]}}
+ {{@array.[2].[@#].[1]}}
+ {{@array.[2].[a b]}}
{{#if @foo}}{{/if}}
{{foo/bar/baz ab=cd}}
diff --git a/tests/format/handlebars/path-expressions/literal-expressions.hbs b/tests/format/handlebars/path-expressions/literal-expressions.hbs
index ea2b3caec..9b665d207 100644
--- a/tests/format/handlebars/path-expressions/literal-expressions.hbs
+++ b/tests/format/handlebars/path-expressions/literal-expressions.hbs
@@ -3,6 +3,10 @@
{{array.2.[@#].[1]}}
{{array.2.[a b]}}
{{this.test}}
+ {{@x.y.z}}
+ {{@array.[true]}}
+ {{@array.2.[@#].[1]}}
+ {{@array.2.[a b]}}
{{#if @foo}}
{{/if}}
diff --git a/tests/unit/__snapshots__/visitor-keys.js.snap b/tests/unit/__snapshots__/visitor-keys.js.snap
index 5727c1a17..d783e8526 100644
--- a/tests/unit/__snapshots__/visitor-keys.js.snap
+++ b/tests/unit/__snapshots__/visitor-keys.js.snap
@@ -1165,7 +1165,6 @@ exports[`visitor keys estree-json 1`] = `
exports[`visitor keys glimmer 1`] = `
{
- "AtHead": [],
"AttrNode": [
"value",
],
@@ -1209,9 +1208,7 @@ exports[`visitor keys glimmer 1`] = `
],
"NullLiteral": [],
"NumberLiteral": [],
- "PathExpression": [
- "head",
- ],
+ "PathExpression": [],
"StringLiteral": [],
"SubExpression": [
"path",
@@ -1222,9 +1219,7 @@ exports[`visitor keys glimmer 1`] = `
"body",
],
"TextNode": [],
- "ThisHead": [],
"UndefinedLiteral": [],
- "VarHead": [],
}
`;