Repository: prettier/plugin-xml (js)

Issue:
Drop space before slash in empty elements
Currently, the plug-in enforces a space before the closing slash in empty elements when `xmlSelfClosingTags` is `true`, normalizing `<foo></foo>` and `<foo/>` to `<foo />`.

Some projects prefer the tighter `<foo/>` syntax, so if an option already exists to configure empty tag handling, perhaps a third value could be added to support this convention, like:

- `true` (no space) – `<foo/>`
- `false` – `<foo></foo>`
- `space` (current behavior) – `<foo />`

If so, this setting could also be applied to the [XML declaration](https://www.w3.org/TR/xml/#NT-XMLDecl), to permit 

```xml
<?xml version="1.0" encoding="UTF-8"?>
```

instead of rewriting to insert an extra space before the closing `?>` as noted in #3:

```xml
<?xml version="1.0" encoding="UTF-8" ?>
```

Pull request description:
Bring back the xmlSelfClosingSpace option
Closes #11 again

Patch:
diff --git a/.github/ISSUE_TEMPLATE/formatting.yml b/.github/ISSUE_TEMPLATE/formatting.yml
index 015aea1..a376f56 100644
--- a/.github/ISSUE_TEMPLATE/formatting.yml
+++ b/.github/ISSUE_TEMPLATE/formatting.yml
@@ -27,6 +27,13 @@ body:
         - "ignore"
     validations:
       required: true
+  - type: dropdown
+    attributes:
+      label: xmlSelfClosingSpace
+      description: What value do you have the `xmlSelfClosingSpace` option set to? (Defaults to `true`.)
+      options:
+        - "true"
+        - "false"
   - type: textarea
     attributes:
       label: Input XML
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0ca0a32..4c389ef 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 
 ## [Unreleased]
 
+### Added
+
+- Bring back the `xmlSelfClosingSpace` option.
+
 ## [1.0.2] - 2021-07-17
 
 ### Changed
diff --git a/src/plugin.ts b/src/plugin.ts
index 1d2e5a7..f41b95b 100644
--- a/src/plugin.ts
+++ b/src/plugin.ts
@@ -6,6 +6,13 @@ import printer from "./printer";
 
 // These are the extra options defined by this plugin.
 const options: Plugin["options"] = {
+  xmlSelfClosingSpace: {
+    type: "boolean",
+    category: "XML",
+    default: true,
+    description: "Adds a space before self-closing tags.",
+    since: "1.1.0"
+  },
   xmlWhitespaceSensitivity: {
     type: "choice",
     category: "XML",
diff --git a/src/printer.ts b/src/printer.ts
index c1c3849..425c033 100644
--- a/src/printer.ts
+++ b/src/printer.ts
@@ -271,7 +271,7 @@ const printer: Printer = {
 
         // Determine the value that will go between the <, name, and attributes
         // of an element and the /> of an element.
-        const space: Doc = opts.bracketSameLine ? " " : line;
+        const space: Doc = opts.xmlSelfClosingSpace ? line : softline;
 
         if (SLASH_CLOSE) {
           return group([...parts, space, SLASH_CLOSE[0].image]);
@@ -446,7 +446,8 @@ const printer: Printer = {
           );
         }
 
-        return group([...parts, line, SPECIAL_CLOSE[0].image]);
+        const space = opts.xmlSelfClosingSpace ? line : softline;
+        return group([...parts, space, SPECIAL_CLOSE[0].image]);
       }
     }
   }
diff --git a/src/types.ts b/src/types.ts
index 69041f9..161f5a7 100644
--- a/src/types.ts
+++ b/src/types.ts
@@ -134,6 +134,7 @@ export type Embed = (
 // the options we defined in our plugin configuration.
 export type Options = Prettier.ParserOptions<any> & {
   bracketSameLine: boolean;
+  xmlSelfClosingSpace: boolean;
   xmlWhitespaceSensitivity: "ignore" | "strict";
 };
 


Test patch:
diff --git a/test/__snapshots__/format.test.ts.snap b/test/__snapshots__/format.test.ts.snap
index 147b0ff..072f22d 100644
--- a/test/__snapshots__/format.test.ts.snap
+++ b/test/__snapshots__/format.test.ts.snap
@@ -76,6 +76,82 @@ use {
 "
 `;
 
+exports[`bracketSameLine => true, xmlSelfClosingSpace => false 1`] = `
+"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
+<!DOCTYPE module PUBLIC \\"-//Puppy Crawl//DTD Check Configuration 1.3//EN\\"
+  \\"https://www.puppycrawl.com/dtds/configuration_1_3.dtd\\">
+<?xml-model href=\\"project.rnc\\" type=\\"application/relax-ng-compact-syntax\\"?>
+<!-- foo -->
+<svg
+  xmlns=\\"http://www.w3.org/2000/svg\\"
+  xmlns:xlink=\\"http://www.w3.org/1999/xlink\\"
+  width=\\"200\\"
+  height=\\"100\\"
+  viewBox=\\"0 0 200 100\\">
+  <title>Style inheritance and the use element</title>
+  <desc _attr=\\"attr\\">
+    &anp; &#12345;
+    <![CDATA[
+      foo
+    ]]>
+    bar
+  </desc>
+  <?pagebreak?>
+
+  <style/>
+  <style/>
+  <style type=\\"text/css\\">
+circle {
+  stroke-opacity: 0.7;
+}
+.special circle {
+  stroke: green;
+}
+use {
+  stroke: purple;
+  fill: orange;
+}
+  </style>
+
+  <yaml
+    myveryveryveryverylongattributename=\\"myveryveryveryverylongattributevalue\\">
+    - 1
+    - 2
+    - 3
+  </style>
+
+  <!-- inner comment -->
+
+  <?pagebreak?>
+  <g class=\\"special\\" style=\\"fill: blue\\">
+    <circle id=\\"c\\" cy=\\"50\\" cx=\\"50\\" r=\\"40\\" stroke-width=\\"20\\"/>
+  </g>
+  <use xlink:href=\\"#c\\" x=\\"100\\"/>
+  <ignored>
+    <!-- prettier-ignore-start -->
+      <   ignored   />
+    <!-- prettier-ignore-end -->
+  </ignored>
+  <p>
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed at est eget
+    enim consectetur accumsan. Aliquam pretium sodales ipsum quis dignissim. Sed
+    id sem vel diam luctus fringilla. Aliquam quis egestas magna. Curabitur
+    molestie lorem et odio porta, et molestie libero laoreet. Morbi rhoncus
+    sagittis cursus. Nullam vehicula pretium consequat. Praesent porta ante at
+    posuere sollicitudin. Nullam commodo tempor arcu, at condimentum neque
+    elementum ut.
+  </p>
+  <span>content</span>
+
+  <div>
+    even more
+    <content/>
+  </div>
+</svg>
+<!-- bar -->
+"
+`;
+
 exports[`defaults 1`] = `
 "<?xml version=\\"1.0\\" encoding=\\"UTF-8\\" ?>
 <!DOCTYPE module PUBLIC \\"-//Puppy Crawl//DTD Check Configuration 1.3//EN\\"
@@ -151,6 +227,84 @@ use {
 "
 `;
 
+exports[`xmlSelfClosingSpace => false 1`] = `
+"<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>
+<!DOCTYPE module PUBLIC \\"-//Puppy Crawl//DTD Check Configuration 1.3//EN\\"
+  \\"https://www.puppycrawl.com/dtds/configuration_1_3.dtd\\">
+<?xml-model href=\\"project.rnc\\" type=\\"application/relax-ng-compact-syntax\\"?>
+<!-- foo -->
+<svg
+  xmlns=\\"http://www.w3.org/2000/svg\\"
+  xmlns:xlink=\\"http://www.w3.org/1999/xlink\\"
+  width=\\"200\\"
+  height=\\"100\\"
+  viewBox=\\"0 0 200 100\\"
+>
+  <title>Style inheritance and the use element</title>
+  <desc _attr=\\"attr\\">
+    &anp; &#12345;
+    <![CDATA[
+      foo
+    ]]>
+    bar
+  </desc>
+  <?pagebreak?>
+
+  <style/>
+  <style/>
+  <style type=\\"text/css\\">
+circle {
+  stroke-opacity: 0.7;
+}
+.special circle {
+  stroke: green;
+}
+use {
+  stroke: purple;
+  fill: orange;
+}
+  </style>
+
+  <yaml
+    myveryveryveryverylongattributename=\\"myveryveryveryverylongattributevalue\\"
+  >
+    - 1
+    - 2
+    - 3
+  </style>
+
+  <!-- inner comment -->
+
+  <?pagebreak?>
+  <g class=\\"special\\" style=\\"fill: blue\\">
+    <circle id=\\"c\\" cy=\\"50\\" cx=\\"50\\" r=\\"40\\" stroke-width=\\"20\\"/>
+  </g>
+  <use xlink:href=\\"#c\\" x=\\"100\\"/>
+  <ignored>
+    <!-- prettier-ignore-start -->
+      <   ignored   />
+    <!-- prettier-ignore-end -->
+  </ignored>
+  <p>
+    Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed at est eget
+    enim consectetur accumsan. Aliquam pretium sodales ipsum quis dignissim. Sed
+    id sem vel diam luctus fringilla. Aliquam quis egestas magna. Curabitur
+    molestie lorem et odio porta, et molestie libero laoreet. Morbi rhoncus
+    sagittis cursus. Nullam vehicula pretium consequat. Praesent porta ante at
+    posuere sollicitudin. Nullam commodo tempor arcu, at condimentum neque
+    elementum ut.
+  </p>
+  <span>content</span>
+
+  <div>
+    even more
+    <content/>
+  </div>
+</svg>
+<!-- bar -->
+"
+`;
+
 exports[`xmlWhitespaceSensitivity => ignore 1`] = `
 "<?xml version=\\"1.0\\" encoding=\\"UTF-8\\" ?>
 <!DOCTYPE module PUBLIC \\"-//Puppy Crawl//DTD Check Configuration 1.3//EN\\"
diff --git a/test/format.test.ts b/test/format.test.ts
index ac200db..058ff58 100644
--- a/test/format.test.ts
+++ b/test/format.test.ts
@@ -33,3 +33,22 @@ test("bracketSameLine => true", () => {
 
   expect(formatted).toMatchSnapshot();
 });
+
+test("xmlSelfClosingSpace => false", () => {
+  const formatted = format(fixture, {
+    xmlSelfClosingSpace: false,
+    xmlWhitespaceSensitivity: "ignore"
+  });
+
+  expect(formatted).toMatchSnapshot();
+});
+
+test("bracketSameLine => true, xmlSelfClosingSpace => false", () => {
+  const formatted = format(fixture, {
+    bracketSameLine: true,
+    xmlSelfClosingSpace: false,
+    xmlWhitespaceSensitivity: "ignore"
+  });
+
+  expect(formatted).toMatchSnapshot();
+});