Repository: prettier/prettier (JavaScript)

Issue:
Glimmer: Named blocks without content are self-closed on format
**Prettier 2.5.0**
[Playground link](https://prettier.io/playground/#N4Igxg9gdgLgprEAuEAeAwhAtgB2gmAdQEsYALAOQEMs4ATAIQBsIwBrAZwD4AdKAAn6okAM2IAnDjAC0UGvWkAjFuy6oA9KIlTZ8ukpVteAoUg5xIUfXNr7lrI0M3nL1vQYfHBwmwvvtpAHdSMmlILFpYLmBgAEJ+ABEIfigIGH5LADc4cXSYZKoBOFwYAE9+OCZiggBfGo0kXztDIJCw7EiYL1MmjwDg8nbYAi4ACUqWBt7-NlbBy3govg1MXHxYEnJqW2YHbj4+GPjU8SwqJgqqzo5+QIhxNn4qG7gADxwLeDp+OuW6YkyanU-0BBygR34AEl0uZijd8vwRBAmCxAvxyHB+Bx5PwWABzYhgJ43cJ4KAEG7qfgABWeYHO6Ge9Eu1VgHAA-D8astVmSCJsyBAAK4wTDDKIrbB8jYhYWi6CLLrLMgTCBAlUotVgkAAGhAEBwMGI0A4yFAVHE4gggVp4gQppQ50CVFKpr1inEVHYcBgAGV5AAZYjk5Aic7md2e71+nBe4N40PhuB64qKeh0egBwp4oVUPFwABi9zOMCNUATjpFEF1IDIMCwTEIZFIcA4sbAcF99tIANIpWQ4A4bpAwfMuWpnrxZ0TTAjIAAVhxXr741UAIpCtJwGdz2OSHIDvFMYgRA96nDiYNEYh0cjIAAcAAZz1bzIRPTgB06XcOAI6b+AJwNB0QGeWQ4Hoegaztf8JDgCc82nUQkz1cwsGIZAYHEIVkxADhVzgDctx3XCYCoRQSFvMhkAAJj1LCqGIY9y1WJCQFbABWGshXMAAVciHTDWdcMyHDISsAhfTAS9DQAQSsX0yiqEi9UXV4GCjNgfX9WggxDZDhLqIA)
<!-- prettier-ignore -->
```sh
--parser glimmer
--no-bracket-spacing
--prose-wrap always
```

**Input:**
<!-- prettier-ignore -->
```hbs
<ComponentWithNamedBlocks>
  <:first-named-block></:first-named-block>
  <:second-named-block> </:second-named-block>
  <:named-block-with-comment>{{! Do not convert to an empty element}}</:named-block-with-comment>
  <:named-block-with-content>Hello</:named-block-with-content>
</ComponentWithNamedBlocks>

{{! normal elements work as expected }}
<div></div>

{{! It seems to follow the same logic as components / PascalCased elements? }}
<ComponentWithoutContent></ComponentWithoutContent>
<hello></hello>


```

**Output:**
<!-- prettier-ignore -->
```hbs
<ComponentWithNamedBlocks>
  <:first-named-block />
  <:second-named-block />
  <:named-block-with-comment
  >{{! Do not convert to an empty element}}</:named-block-with-comment>
  <:named-block-with-content>Hello</:named-block-with-content>
</ComponentWithNamedBlocks>

{{! normal elements work as expected }}
<div></div>

{{! It seems to follow the same logic as components / PascalCased elements? }}
<ComponentWithoutContent />
<hello></hello>
```

**Expected behavior:**
```hbs
<ComponentWithNamedBlocks>
  <:first-named-block></:first-named-block>
  <:second-named-block> </:second-named-block>
  <:named-block-with-comment
  >{{! Do not convert to an empty element}}</:named-block-with-comment>
  <:named-block-with-content>Hello</:named-block-with-content>
</ComponentWithNamedBlocks>

{{! normal elements work as expected }}
<div></div>

{{! It seems to follow the same logic as components / PascalCased elements? }}
<ComponentWithoutContent />
<hello></hello>
```
Ember 3.25 enabled the yieldable named blocks feature which is explained in [this RFC](https://emberjs.github.io/rfcs/0460-yieldable-named-blocks.html).

Prettier does support the syntax already, but there is one case that doesn't work as expected: If a named block doesn't have any content Prettier will convert it to its self-closing equivalent (which seems to mimic the behavior for components in the Angle Bracket Invocation). The problem is that the Glimmer template compiler doesn't support self-closing named blocks and throws an error.

`<:named-block-name/> is not a valid named block: named blocks cannot be self-closing`.

So I think the named blocks should be treated the same as normal HTML elements instead of as components. The easiest way around this is to add a comment to the named block so that it will be not formatted as a self-closing element.


Hints:
Hi @Windvis, thanks for the detailed report!

For reference, even though the RFC allegedly supports self-closing named blocks, it stopped supporting later (https://github.com/glimmerjs/glimmer-vm/commit/7f8b6384d4ff1ff0c14d1c64585fb86be47e2bd4).

Patch:
diff --git a/src/language-handlebars/utils.js b/src/language-handlebars/utils.js
--- a/src/language-handlebars/utils.js
+++ b/src/language-handlebars/utils.js
@@ -32,6 +32,7 @@ function isGlimmerComponent(node) {
   return (
     isNodeOfSomeType(node, ["ElementNode"]) &&
     typeof node.tag === "string" &&
+    node.tag[0] !== ":" &&
     (isUppercase(node.tag[0]) || node.tag.includes("."))
   );
 }


Test patch:
diff --git a/tests/format/handlebars/basics/__snapshots__/jsfmt.spec.js.snap b/tests/format/handlebars/basics/__snapshots__/jsfmt.spec.js.snap
--- a/tests/format/handlebars/basics/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/format/handlebars/basics/__snapshots__/jsfmt.spec.js.snap
@@ -93,6 +93,30 @@ printWidth: 80
 ================================================================================
 `;
 
+exports[`named-block.hbs format 1`] = `
+====================================options=====================================
+parsers: ["glimmer"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+<ComponentWithNamedBlocks>
+  <:first-named-block></:first-named-block>
+  <:second-named-block> </:second-named-block>
+  <:named-block-with-comment>{{! Do not convert to an empty element}}</:named-block-with-comment>
+  <:named-block-with-content>Hello</:named-block-with-content>
+</ComponentWithNamedBlocks>
+
+=====================================output=====================================
+<ComponentWithNamedBlocks>
+  <:first-named-block></:first-named-block>
+  <:second-named-block> </:second-named-block>
+  <:named-block-with-comment
+  >{{! Do not convert to an empty element}}</:named-block-with-comment>
+  <:named-block-with-content>Hello</:named-block-with-content>
+</ComponentWithNamedBlocks>
+================================================================================
+`;
+
 exports[`nested-path.hbs format 1`] = `
 ====================================options=====================================
 parsers: ["glimmer"]
diff --git a/tests/format/handlebars/basics/named-block.hbs b/tests/format/handlebars/basics/named-block.hbs
new file mode 100644
--- /dev/null
+++ b/tests/format/handlebars/basics/named-block.hbs
@@ -0,0 +1,6 @@
+<ComponentWithNamedBlocks>
+  <:first-named-block></:first-named-block>
+  <:second-named-block> </:second-named-block>
+  <:named-block-with-comment>{{! Do not convert to an empty element}}</:named-block-with-comment>
+  <:named-block-with-content>Hello</:named-block-with-content>
+</ComponentWithNamedBlocks>