Repository: prettier/prettier (JavaScript)
Date: 2019-01-01 08:51:50+00:00
Task type: Feature

Issue:
markdown : compact formatted table
**Prettier 1.15.3**
**Input:**
```
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| addon | called from timepicker panel to render some addon to its bottom | function | - |
| allowEmpty | allow clearing text | boolean | true |
| autoFocus | get focus when component mounted | boolean | false |
| className | className of picker | string | '' |
| clearText | clear tooltip of icon | string | clear |
| defaultOpenValue | default open panel value, used to set utcOffset,locale if value/defaultValue absent | [moment](http://momentjs.com/) | moment() |
| defaultValue | to set default time | [moment](http://momentjs.com/) | - |
| disabled | determine whether the TimePicker is disabled | boolean | false |
| disabledHours | to specify the hours that cannot be selected | function() | - |
| disabledMinutes | to specify the minutes that cannot be selected | function(selectedHour) | - |
| disabledSeconds | to specify the seconds that cannot be selected | function(selectedHour, selectedMinute) | - |
| format | to set the time format | string | "HH:mm:ss" |
| getPopupContainer | to set the container of the floating layer, while the default is to create a div element in body | function(trigger) | - |
| hideDisabledOptions | hide the options that can not be selected | boolean | false |
| hourStep | interval between hours in picker | number | 1 |
| inputReadOnly | Set the `readonly` attribute of the input tag (avoids virtual keyboard on touch devices) | boolean | false |
```

**Output:**
```
| Property            | Description                                                                                      | Type                                   | Default    |
| ------------------- | ------------------------------------------------------------------------------------------------ | -------------------------------------- | ---------- |
| addon               | called from timepicker panel to render some addon to its bottom                                  | function                               | -          |
| allowEmpty          | allow clearing text                                                                              | boolean                                | true       |
| autoFocus           | get focus when component mounted                                                                 | boolean                                | false      |
| className           | className of picker                                                                              | string                                 | ''         |
| clearText           | clear tooltip of icon                                                                            | string                                 | clear      |
| defaultOpenValue    | default open panel value, used to set utcOffset,locale if value/defaultValue absent              | [moment](http://momentjs.com/)         | moment()   |
| defaultValue        | to set default time                                                                              | [moment](http://momentjs.com/)         | -          |
| disabled            | determine whether the TimePicker is disabled                                                     | boolean                                | false      |
| disabledHours       | to specify the hours that cannot be selected                                                     | function()                             | -          |
| disabledMinutes     | to specify the minutes that cannot be selected                                                   | function(selectedHour)                 | -          |
| disabledSeconds     | to specify the seconds that cannot be selected                                                   | function(selectedHour, selectedMinute) | -          |
| format              | to set the time format                                                                           | string                                 | "HH:mm:ss" |
| getPopupContainer   | to set the container of the floating layer, while the default is to create a div element in body | function(trigger)                      | -          |
| hideDisabledOptions | hide the options that can not be selected                                                        | boolean                                | false      |
| hourStep            | interval between hours in picker                                                                 | number                                 | 1          |
| inputReadOnly       | Set the `readonly` attribute of the input tag (avoids virtual keyboard on touch devices)         | boolean                                | false      |

```

**Expected behavior:**

I need a compact formatted table.
It made me unable to format all the code.





Issue discussion:
![image](https://user-images.githubusercontent.com/8186664/50086141-188f1d80-0237-11e9-8846-a714a6da7803.png)

![image](https://user-images.githubusercontent.com/8186664/50086164-2775d000-0237-11e9-8e54-32472decdba5.png)

I think compact is a better solution for api table
Feel free to use `<!-- prettier-ignore -->` to stop Prettier from formatting this table. Personally, an aligned table is easier for me to read, although we could compress tables wider than the `printWidth`.
Thank you for your reply.
Would it be better to add a compact config?
We try not to add new options: https://prettier.io/docs/en/option-philosophy.html#docsNav
We have a lot of such [table](https://github.com/ant-design/ant-design/search?l=Markdown). 
It would be great if you could provide quick access to the configuration.

> although we could compress tables wider than the printWidth.

This may be a better solution, I agree with him
In our markdown file, the width of table line is very long. It cause unreadable than collapsed one...

Solution patch:
diff --git a/CHANGELOG.unreleased.md b/CHANGELOG.unreleased.md
index 7b5a8f5be608..764e3973be7a 100644
--- a/CHANGELOG.unreleased.md
+++ b/CHANGELOG.unreleased.md
@@ -41,3 +41,33 @@ Examples:
   ```
 
 -->
+
+- Markdown: Do not align table contents if it exceeds the print width and `--prose-wrap never` is set ([#5701] by [@chenshuai2144])
+
+  The aligned table is less readable than the compact one
+  if it's particularly long and the word wrapping is not enabled in the editor
+  so we now print them as compact tables in these situations.
+
+  <!-- prettier-ignore -->
+  ```md
+  <!-- Input -->
+  | Property | Description | Type | Default |
+  | -------- | ----------- | ---- | ------- |
+  | bordered | Toggles rendering of the border around the list | boolean | false |
+  | itemLayout | The layout of list, default is `horizontal`, If a vertical list is desired, set the itemLayout property to `vertical` | string | - |
+
+  <!-- Output (Prettier stable, --prose-wrap never) -->
+  | Property   | Description                                                                                                           | Type    | Default |
+  | ---------- | --------------------------------------------------------------------------------------------------------------------- | ------- | ------- |
+  | bordered   | Toggles rendering of the border around the list                                                                       | boolean | false   |
+  | itemLayout | The layout of list, default is `horizontal`, If a vertical list is desired, set the itemLayout property to `vertical` | string  | -       |
+
+  <!-- Output (Prettier master, --prose-wrap never) -->
+  | Property | Description | Type | Default |
+  | --- | --- | --- | --- |
+  | bordered | Toggles rendering of the border around the list | boolean | false |
+  | itemLayout | The layout of list, default is `horizontal`, If a vertical list is desired, set the itemLayout property to `vertical` | string | - |
+  ```
+
+[@chenshuai2144]: https://github.com/chenshuai2144
+[#5701]: https://github.com/prettier/prettier/pull/5701
diff --git a/src/language-markdown/printer-markdown.js b/src/language-markdown/printer-markdown.js
index 40f036569e0c..9b7ba4b8e6f4 100644
--- a/src/language-markdown/printer-markdown.js
+++ b/src/language-markdown/printer-markdown.js
@@ -6,6 +6,7 @@ const pragma = require("./pragma");
 const preprocess = require("./preprocess");
 const {
   builders: {
+    breakParent,
     concat,
     join,
     line,
@@ -13,6 +14,7 @@ const {
     markAsRoot,
     hardline,
     softline,
+    ifBreak,
     fill,
     align,
     indent,
@@ -509,6 +511,7 @@ function printLine(path, value, options) {
 }
 
 function printTable(path, options, print) {
+  const hardlineWithoutBreakParent = hardline.parts[0];
   const node = path.getValue();
   const contents = []; // { [rowIndex: number]: { [columnIndex: number]: string } }
 
@@ -524,6 +527,7 @@ function printTable(path, options, print) {
     contents.push(rowContents);
   }, "children");
 
+  // Get the width of each column
   const columnMaxWidths = contents.reduce(
     (currentWidths, rowContents) =>
       currentWidths.map((width, columnIndex) =>
@@ -531,28 +535,49 @@ function printTable(path, options, print) {
       ),
     contents[0].map(() => 3) // minimum width = 3 (---, :--, :-:, --:)
   );
-
-  return join(hardline, [
+  const alignedTable = join(hardlineWithoutBreakParent, [
     printRow(contents[0]),
     printSeparator(),
-    join(hardline, contents.slice(1).map(printRow))
+    join(
+      hardlineWithoutBreakParent,
+      contents.slice(1).map(rowContents => printRow(rowContents))
+    )
+  ]);
+
+  if (options.proseWrap !== "never") {
+    return concat([breakParent, alignedTable]);
+  }
+
+  // Only if the --prose-wrap never is set and it exceeds the print width.
+  const compactTable = join(hardlineWithoutBreakParent, [
+    printRow(contents[0], /* isCompact */ true),
+    printSeparator(/* isCompact */ true),
+    join(
+      hardlineWithoutBreakParent,
+      contents
+        .slice(1)
+        .map(rowContents => printRow(rowContents, /* isCompact */ true))
+    )
   ]);
 
-  function printSeparator() {
+  return concat([breakParent, group(ifBreak(compactTable, alignedTable))]);
+
+  function printSeparator(isCompact) {
     return concat([
       "| ",
       join(
         " | ",
         columnMaxWidths.map((width, index) => {
+          const spaces = isCompact ? 3 : width;
           switch (node.align[index]) {
             case "left":
-              return ":" + "-".repeat(width - 1);
+              return ":" + "-".repeat(spaces - 1);
             case "right":
-              return "-".repeat(width - 1) + ":";
+              return "-".repeat(spaces - 1) + ":";
             case "center":
-              return ":" + "-".repeat(width - 2) + ":";
+              return ":" + "-".repeat(spaces - 2) + ":";
             default:
-              return "-".repeat(width);
+              return "-".repeat(spaces);
           }
         })
       ),
@@ -560,32 +585,36 @@ function printTable(path, options, print) {
     ]);
   }
 
-  function printRow(rowContents) {
+  function printRow(rowContents, isCompact) {
     return concat([
       "| ",
       join(
         " | ",
-        rowContents.map((rowContent, columnIndex) => {
-          switch (node.align[columnIndex]) {
-            case "right":
-              return alignRight(rowContent, columnMaxWidths[columnIndex]);
-            case "center":
-              return alignCenter(rowContent, columnMaxWidths[columnIndex]);
-            default:
-              return alignLeft(rowContent, columnMaxWidths[columnIndex]);
-          }
-        })
+        isCompact
+          ? rowContents
+          : rowContents.map((rowContent, columnIndex) => {
+              switch (node.align[columnIndex]) {
+                case "right":
+                  return alignRight(rowContent, columnMaxWidths[columnIndex]);
+                case "center":
+                  return alignCenter(rowContent, columnMaxWidths[columnIndex]);
+                default:
+                  return alignLeft(rowContent, columnMaxWidths[columnIndex]);
+              }
+            })
       ),
       " |"
     ]);
   }
 
   function alignLeft(text, width) {
-    return concat([text, " ".repeat(width - privateUtil.getStringWidth(text))]);
+    const spaces = width - privateUtil.getStringWidth(text);
+    return concat([text, " ".repeat(spaces)]);
   }
 
   function alignRight(text, width) {
-    return concat([" ".repeat(width - privateUtil.getStringWidth(text)), text]);
+    const spaces = width - privateUtil.getStringWidth(text);
+    return concat([" ".repeat(spaces), text]);
   }
 
   function alignCenter(text, width) {


Test patch:
diff --git a/tests/markdown_long_table/__snapshots__/jsfmt.spec.js.snap b/tests/markdown_long_table/__snapshots__/jsfmt.spec.js.snap
new file mode 100644
index 000000000000..1b3fe4c5e98a
--- /dev/null
+++ b/tests/markdown_long_table/__snapshots__/jsfmt.spec.js.snap
@@ -0,0 +1,76 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`long-table.md 1`] = `
+====================================options=====================================
+parsers: ["markdown"]
+printWidth: 80
+                                                                                | printWidth
+=====================================input======================================
+| Property | Description | Type | Default |
+| -------- | ----------- | ---- | ------- |
+| bordered | Toggles rendering of the border around the list | boolean | false |
+| footer | List footer renderer | string\\|ReactNode | - |
+| grid | The grid type of list. You can set grid to something like {gutter: 16, column: 4} | object | - |
+| header | List header renderer | string\\|ReactNode | - |
+| itemLayout | The layout of list, default is \`horizontal\`, If a vertical list is desired, set the itemLayout property to \`vertical\` | string | - |
+| rowKey | Item's unique key, could be a string or function that returns a string | string\\|Function(record):string | \`key\` |
+| loading | Shows a loading indicator while the contents of the list are being fetched | boolean\\|[object](https://ant.design/components/spin-cn/#API) ([more](https://github.com/ant-design/ant-design/issues/8659)) | false |
+| loadMore | Shows a load more content | string\\|ReactNode | - |
+| locale | i18n text including empty text | object | emptyText: 'No Data' <br> |
+| pagination | Pagination [config](https://ant.design/components/pagination/), hide it by setting it to false | boolean \\| object | false |
+| split | Toggles rendering of the split under the list item | boolean | true |
+=====================================output=====================================
+| Property   | Description                                                                                                           | Type                                                                                                                         | Default                   |
+| ---------- | --------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ------------------------- |
+| bordered   | Toggles rendering of the border around the list                                                                       | boolean                                                                                                                      | false                     |
+| footer     | List footer renderer                                                                                                  | string\\|ReactNode                                                                                                            | -                         |
+| grid       | The grid type of list. You can set grid to something like {gutter: 16, column: 4}                                     | object                                                                                                                       | -                         |
+| header     | List header renderer                                                                                                  | string\\|ReactNode                                                                                                            | -                         |
+| itemLayout | The layout of list, default is \`horizontal\`, If a vertical list is desired, set the itemLayout property to \`vertical\` | string                                                                                                                       | -                         |
+| rowKey     | Item's unique key, could be a string or function that returns a string                                                | string\\|Function(record):string                                                                                              | \`key\`                     |
+| loading    | Shows a loading indicator while the contents of the list are being fetched                                            | boolean\\|[object](https://ant.design/components/spin-cn/#API) ([more](https://github.com/ant-design/ant-design/issues/8659)) | false                     |
+| loadMore   | Shows a load more content                                                                                             | string\\|ReactNode                                                                                                            | -                         |
+| locale     | i18n text including empty text                                                                                        | object                                                                                                                       | emptyText: 'No Data' <br> |
+| pagination | Pagination [config](https://ant.design/components/pagination/), hide it by setting it to false                        | boolean \\| object                                                                                                            | false                     |
+| split      | Toggles rendering of the split under the list item                                                                    | boolean                                                                                                                      | true                      |
+
+================================================================================
+`;
+
+exports[`long-table.md 2`] = `
+====================================options=====================================
+parsers: ["markdown"]
+printWidth: 80
+proseWrap: "never"
+                                                                                | printWidth
+=====================================input======================================
+| Property | Description | Type | Default |
+| -------- | ----------- | ---- | ------- |
+| bordered | Toggles rendering of the border around the list | boolean | false |
+| footer | List footer renderer | string\\|ReactNode | - |
+| grid | The grid type of list. You can set grid to something like {gutter: 16, column: 4} | object | - |
+| header | List header renderer | string\\|ReactNode | - |
+| itemLayout | The layout of list, default is \`horizontal\`, If a vertical list is desired, set the itemLayout property to \`vertical\` | string | - |
+| rowKey | Item's unique key, could be a string or function that returns a string | string\\|Function(record):string | \`key\` |
+| loading | Shows a loading indicator while the contents of the list are being fetched | boolean\\|[object](https://ant.design/components/spin-cn/#API) ([more](https://github.com/ant-design/ant-design/issues/8659)) | false |
+| loadMore | Shows a load more content | string\\|ReactNode | - |
+| locale | i18n text including empty text | object | emptyText: 'No Data' <br> |
+| pagination | Pagination [config](https://ant.design/components/pagination/), hide it by setting it to false | boolean \\| object | false |
+| split | Toggles rendering of the split under the list item | boolean | true |
+=====================================output=====================================
+| Property | Description | Type | Default |
+| --- | --- | --- | --- |
+| bordered | Toggles rendering of the border around the list | boolean | false |
+| footer | List footer renderer | string\\|ReactNode | - |
+| grid | The grid type of list. You can set grid to something like {gutter: 16, column: 4} | object | - |
+| header | List header renderer | string\\|ReactNode | - |
+| itemLayout | The layout of list, default is \`horizontal\`, If a vertical list is desired, set the itemLayout property to \`vertical\` | string | - |
+| rowKey | Item's unique key, could be a string or function that returns a string | string\\|Function(record):string | \`key\` |
+| loading | Shows a loading indicator while the contents of the list are being fetched | boolean\\|[object](https://ant.design/components/spin-cn/#API) ([more](https://github.com/ant-design/ant-design/issues/8659)) | false |
+| loadMore | Shows a load more content | string\\|ReactNode | - |
+| locale | i18n text including empty text | object | emptyText: 'No Data' <br> |
+| pagination | Pagination [config](https://ant.design/components/pagination/), hide it by setting it to false | boolean \\| object | false |
+| split | Toggles rendering of the split under the list item | boolean | true |
+
+================================================================================
+`;
diff --git a/tests/markdown_long_table/jsfmt.spec.js b/tests/markdown_long_table/jsfmt.spec.js
new file mode 100644
index 000000000000..e1c94789f9d1
--- /dev/null
+++ b/tests/markdown_long_table/jsfmt.spec.js
@@ -0,0 +1,2 @@
+run_spec(__dirname, ["markdown"]);
+run_spec(__dirname, ["markdown"], { proseWrap: "never" });
diff --git a/tests/markdown_long_table/long-table.md b/tests/markdown_long_table/long-table.md
new file mode 100644
index 000000000000..57ff8ab25fe5
--- /dev/null
+++ b/tests/markdown_long_table/long-table.md
@@ -0,0 +1,13 @@
+| Property | Description | Type | Default |
+| -------- | ----------- | ---- | ------- |
+| bordered | Toggles rendering of the border around the list | boolean | false |
+| footer | List footer renderer | string\|ReactNode | - |
+| grid | The grid type of list. You can set grid to something like {gutter: 16, column: 4} | object | - |
+| header | List header renderer | string\|ReactNode | - |
+| itemLayout | The layout of list, default is `horizontal`, If a vertical list is desired, set the itemLayout property to `vertical` | string | - |
+| rowKey | Item's unique key, could be a string or function that returns a string | string\|Function(record):string | `key` |
+| loading | Shows a loading indicator while the contents of the list are being fetched | boolean\|[object](https://ant.design/components/spin-cn/#API) ([more](https://github.com/ant-design/ant-design/issues/8659)) | false |
+| loadMore | Shows a load more content | string\|ReactNode | - |
+| locale | i18n text including empty text | object | emptyText: 'No Data' <br> |
+| pagination | Pagination [config](https://ant.design/components/pagination/), hide it by setting it to false | boolean \| object | false |
+| split | Toggles rendering of the split under the list item | boolean | true |
\ No newline at end of file
diff --git a/tests/markdown_table/__snapshots__/jsfmt.spec.js.snap b/tests/markdown_table/__snapshots__/jsfmt.spec.js.snap
index e4eb22d771a4..aa3638a50938 100644
--- a/tests/markdown_table/__snapshots__/jsfmt.spec.js.snap
+++ b/tests/markdown_table/__snapshots__/jsfmt.spec.js.snap
@@ -134,3 +134,45 @@ proseWrap: "always"
 
 ================================================================================
 `;
+
+exports[`table.md 1`] = `
+====================================options=====================================
+parsers: ["markdown"]
+printWidth: 80
+proseWrap: "always"
+                                                                                | printWidth
+=====================================input======================================
+- min-table
+
+  | Age | Time | Food | Gold | Requirement |
+  | ------------ | ----- | ---- | ---- | ----------------------- |
+  | Feudal Age | 02:10 | 500 | 0 | Dark Age building x 2 |
+  | Castle Age | 02:40 | 800 | 200 |- |
+  | Imperial Age | 03:30 | 1000 | 800 | Castle Age building x 2 |
+- big-table
+
+  |学号|姓名|分数|
+  |-|-|-|
+  |小明|男|75|
+  |小红|女|79|
+  |小陆|男|92|
+
+=====================================output=====================================
+- min-table
+
+  | Age          | Time  | Food | Gold | Requirement             |
+  | ------------ | ----- | ---- | ---- | ----------------------- |
+  | Feudal Age   | 02:10 | 500  | 0    | Dark Age building x 2   |
+  | Castle Age   | 02:40 | 800  | 200  | -                       |
+  | Imperial Age | 03:30 | 1000 | 800  | Castle Age building x 2 |
+
+- big-table
+
+  | 学号 | 姓名 | 分数 |
+  | ---- | ---- | ---- |
+  | 小明 | 男   | 75   |
+  | 小红 | 女   | 79   |
+  | 小陆 | 男   | 92   |
+
+================================================================================
+`;
diff --git a/tests/markdown_table/table.md b/tests/markdown_table/table.md
new file mode 100644
index 000000000000..2096adf14c89
--- /dev/null
+++ b/tests/markdown_table/table.md
@@ -0,0 +1,14 @@
+- min-table
+
+  | Age | Time | Food | Gold | Requirement |
+  | ------------ | ----- | ---- | ---- | ----------------------- |
+  | Feudal Age | 02:10 | 500 | 0 | Dark Age building x 2 |
+  | Castle Age | 02:40 | 800 | 200 |- |
+  | Imperial Age | 03:30 | 1000 | 800 | Castle Age building x 2 |
+- big-table
+
+  |学号|姓名|分数|
+  |-|-|-|
+  |小明|男|75|
+  |小红|女|79|
+  |小陆|男|92|