Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(markdown): add proseWrap: "preserve" option #3340

Merged
merged 12 commits into from
Dec 1, 2017
14 changes: 10 additions & 4 deletions docs/options.md
Original file line number Diff line number Diff line change
Expand Up @@ -203,8 +203,14 @@ Prettier can insert a special @format marker at the top of files specifying that

_available in v1.8.2+_

By default, Prettier will wrap markdown text at the specified print width. In some cases you may want to rely on editor/viewer soft wrapping instead, so this option allows you to opt out. When prose wrapping is disabled, each paragraph will be printed on its own line.
By default, Prettier will wrap markdown text as-is since some services use a linebreak-sensitive renderer, e.g. GitHub comment and BitBucket. In some cases you may want to rely on editor/viewer soft wrapping instead, so this option allows you to opt out with `"never"`.

| Default | CLI Override | API Override |
| ------- | ----------------- | ------------------- |
| `true` | `--no-prose-wrap` | `proseWrap: <bool>` |
Valid options:

* `"always"` - Wrap prose if it exceeds the print width.
* `"never"` - Do not wrap prose.
* `"preserve"` - Wrap prose as-is. _available in v1.9.0+_

| Default | CLI Override | API Override |
| ------------ | ----------------------------------------------------------- | ----------------------------------------------------------- |
| `"preserve"` | <code>--prose-wrap <always&#124;never&#124;preserve></code> | <code>proseWrap: "<always&#124;never&#124;preserve>"</code> |
4 changes: 4 additions & 0 deletions src/clean-ast.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@ function massageAST(ast, parent) {
if (ast.type === "code") {
delete newObj.value;
}
// for markdown whitespace: "\n" and " " are considered the same
if (ast.type === "whitespace" && ast.value === "\n") {
newObj.value = " ";
}

if (
ast.type === "media-query" ||
Expand Down
14 changes: 11 additions & 3 deletions src/cli-constant.js
Original file line number Diff line number Diff line change
Expand Up @@ -237,11 +237,19 @@ const detailedOptions = normalizeDetailedOptions({
description: "The line length where Prettier will try wrap."
},
"prose-wrap": {
type: "boolean",
type: "choice",
category: CATEGORY_FORMAT,
forwardToApi: true,
description: "Wrap prose if it exceeds the print width. (markdown)",
oppositeDescription: "Do not wrap prose. (markdown)"
description: "How to wrap prose. (markdown)",
choices: [
{
value: "always",
description: "Wrap prose if it exceeds the print width."
},
{ value: "never", description: "Do not wrap prose." },
{ value: "preserve", description: "Wrap prose as-is." },
{ value: false, deprecated: true, redirect: "never" }
]
},
"range-end": {
type: "int",
Expand Down
12 changes: 11 additions & 1 deletion src/options.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const defaults = {
insertPragma: false,
requirePragma: false,
semi: true,
proseWrap: true,
proseWrap: "preserve",
arrowParens: "avoid"
};

Expand Down Expand Up @@ -72,6 +72,16 @@ function normalize(options) {
);
}

/* istanbul ignore if */
if (typeof normalized.proseWrap === "boolean") {
normalized.proseWrap = normalized.proseWrap ? "always" : "never";

console.warn(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we still use deprecated.js? It seems to be outdated.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems it's only used for useFlowParser warning.

I think we can refactor those option warnings/redirections using #3352.

"Warning: `proseWrap` with boolean value is deprecated. " +
'Use "always", "never", or "preserve" instead.'
);
}

/* istanbul ignore if */
if (normalized.parser === "postcss") {
normalized.parser = "css";
Expand Down
24 changes: 15 additions & 9 deletions src/printer-markdown.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ function genericPrint(path, options, print) {
node =>
node.type === "word"
? node.value
: node.value === "" ? "" : printLine(path, line, options)
: node.value === "" ? "" : printLine(path, node.value, options)
)
);
}
Expand Down Expand Up @@ -98,12 +98,13 @@ function genericPrint(path, options, print) {
const index = parentNode.children.indexOf(node);
const nextNode = parentNode.children[index + 1];

// leading char that may cause different syntax
if (nextNode && /^>|^([-+*]|#{1,6})$/.test(nextNode.value)) {
return node.value === "" ? "" : " ";
}
const proseWrap =
// leading char that may cause different syntax
nextNode && /^>|^([-+*]|#{1,6})$/.test(nextNode.value)
? "never"
: options.proseWrap;

return printLine(path, node.value === "" ? softline : line, options);
return printLine(path, node.value, { proseWrap });
}
case "emphasis": {
const parentNode = path.getParentNode();
Expand Down Expand Up @@ -366,10 +367,15 @@ function getAncestorNode(path, typeOrTypes) {
return counter === -1 ? null : path.getParentNode(counter);
}

function printLine(path, lineOrSoftline, options) {
function printLine(path, value, options) {
if (options.proseWrap === "preserve" && value === "\n") {
return hardline;
}

const isBreakable =
options.proseWrap && !getAncestorNode(path, SINGLE_LINE_NODE_TYPES);
return lineOrSoftline === line
options.proseWrap === "always" &&
!getAncestorNode(path, SINGLE_LINE_NODE_TYPES);
return value !== ""
? isBreakable ? line : " "
: isBreakable ? softline : "";
}
Expand Down
7 changes: 5 additions & 2 deletions src/util.js
Original file line number Diff line number Diff line change
Expand Up @@ -672,7 +672,7 @@ function mapDoc(doc, callback) {
/**
* split text into whitespaces and words
* @param {string} text
* @return {Array<{ type: "whitespace", value: " " | "" } | { type: "word", value: string }>}
* @return {Array<{ type: "whitespace", value: " " | "\n" | "" } | { type: "word", value: string }>}
*/
function splitText(text) {
const KIND_NON_CJK = "non-cjk";
Expand All @@ -687,7 +687,10 @@ function splitText(text) {
.forEach((token, index, tokens) => {
// whitespace
if (index % 2 === 1) {
nodes.push({ type: "whitespace", value: " " });
nodes.push({
type: "whitespace",
value: /\n/.test(token) ? "\n" : " "
});
return;
}

Expand Down
174 changes: 174 additions & 0 deletions tests/markdown_paragraph/__snapshots__/jsfmt.spec.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,33 @@ This ia an english paragraph with a CJK quote “中文“.

`;

exports[`cjk.md 3`] = `
這是一段很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長的段落

這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!這是一個English混合著中文的一段Paragraph!

全  形 空白全  形 空白全  形 空白全  形 空白全  形 空白全  形 空白全  形 空白全  形 空白

This ia an english paragraph with a CJK quote "中文".

This ia an english paragraph with a CJK quote “中文“.

扩展运算符(spread)是三个点(\`...\`)。
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
這是一段很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長很長的段落

這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!這是一個 English 混合著中文的一段 Paragraph!

全  形 空白全  形 空白全  形 空白全  形 空白全  形 空白全  形 空白全  形 空白全  形 空白

This ia an english paragraph with a CJK quote "中文".

This ia an english paragraph with a CJK quote “中文“.

扩展运算符(spread)是三个点(\`...\`)。

`;

exports[`inline-nodes.md 1`] = `
It removes all original styling[*](#styling-footnote) and ensures that all outputted code conforms to a consistent style. (See this [blog post](http://jlongster.com/A-Prettier-Formatter))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -81,6 +108,84 @@ It removes all original styling[\\*](#styling-footnote) and ensures that all out

`;

exports[`inline-nodes.md 3`] = `
It removes all original styling[*](#styling-footnote) and ensures that all outputted code conforms to a consistent style. (See this [blog post](http://jlongster.com/A-Prettier-Formatter))
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It removes all original styling[\\*](#styling-footnote) and ensures that all outputted code conforms to a consistent style. (See this [blog post](http://jlongster.com/A-Prettier-Formatter))

`;

exports[`lorem.md 1`] = `
Hic dicta et recusandae incidunt. Reiciendis saepe voluptatem tempore rem aut.
Iusto sapiente impedit. Laudantium ut id non et aperiam ab.

Sit minus architecto quas quibusdam sed ipsam aut eum.
Dolores tempora reiciendis magni blanditiis laborum aliquid rem corporis enim. Et consectetur quo sed excepturi soluta repudiandae commodi id.
Eum possimus optio distinctio incidunt quasi optio culpa accusamus.
Architecto esse ut aut autem ullam consequatur reiciendis aliquid dolorum.

Et quam mollitia velit iste enim exercitationem nemo.
Hic dignissimos eos et. Eos eos consequatur.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hic dicta et recusandae incidunt. Reiciendis saepe voluptatem tempore rem aut.
Iusto sapiente impedit. Laudantium ut id non et aperiam ab.

Sit minus architecto quas quibusdam sed ipsam aut eum. Dolores tempora
reiciendis magni blanditiis laborum aliquid rem corporis enim. Et consectetur
quo sed excepturi soluta repudiandae commodi id. Eum possimus optio distinctio
incidunt quasi optio culpa accusamus. Architecto esse ut aut autem ullam
consequatur reiciendis aliquid dolorum.

Et quam mollitia velit iste enim exercitationem nemo. Hic dignissimos eos et.
Eos eos consequatur.

`;

exports[`lorem.md 2`] = `
Hic dicta et recusandae incidunt. Reiciendis saepe voluptatem tempore rem aut.
Iusto sapiente impedit. Laudantium ut id non et aperiam ab.

Sit minus architecto quas quibusdam sed ipsam aut eum.
Dolores tempora reiciendis magni blanditiis laborum aliquid rem corporis enim. Et consectetur quo sed excepturi soluta repudiandae commodi id.
Eum possimus optio distinctio incidunt quasi optio culpa accusamus.
Architecto esse ut aut autem ullam consequatur reiciendis aliquid dolorum.

Et quam mollitia velit iste enim exercitationem nemo.
Hic dignissimos eos et. Eos eos consequatur.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hic dicta et recusandae incidunt. Reiciendis saepe voluptatem tempore rem aut. Iusto sapiente impedit. Laudantium ut id non et aperiam ab.

Sit minus architecto quas quibusdam sed ipsam aut eum. Dolores tempora reiciendis magni blanditiis laborum aliquid rem corporis enim. Et consectetur quo sed excepturi soluta repudiandae commodi id. Eum possimus optio distinctio incidunt quasi optio culpa accusamus. Architecto esse ut aut autem ullam consequatur reiciendis aliquid dolorum.

Et quam mollitia velit iste enim exercitationem nemo. Hic dignissimos eos et. Eos eos consequatur.

`;

exports[`lorem.md 3`] = `
Hic dicta et recusandae incidunt. Reiciendis saepe voluptatem tempore rem aut.
Iusto sapiente impedit. Laudantium ut id non et aperiam ab.

Sit minus architecto quas quibusdam sed ipsam aut eum.
Dolores tempora reiciendis magni blanditiis laborum aliquid rem corporis enim. Et consectetur quo sed excepturi soluta repudiandae commodi id.
Eum possimus optio distinctio incidunt quasi optio culpa accusamus.
Architecto esse ut aut autem ullam consequatur reiciendis aliquid dolorum.

Et quam mollitia velit iste enim exercitationem nemo.
Hic dignissimos eos et. Eos eos consequatur.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Hic dicta et recusandae incidunt. Reiciendis saepe voluptatem tempore rem aut.
Iusto sapiente impedit. Laudantium ut id non et aperiam ab.

Sit minus architecto quas quibusdam sed ipsam aut eum.
Dolores tempora reiciendis magni blanditiis laborum aliquid rem corporis enim. Et consectetur quo sed excepturi soluta repudiandae commodi id.
Eum possimus optio distinctio incidunt quasi optio culpa accusamus.
Architecto esse ut aut autem ullam consequatur reiciendis aliquid dolorum.

Et quam mollitia velit iste enim exercitationem nemo.
Hic dignissimos eos et. Eos eos consequatur.

`;

exports[`simple.md 1`] = `
This is a long long long long long long long long long long long long long long long paragraph.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand All @@ -96,6 +201,13 @@ This is a long long long long long long long long long long long long long long

`;

exports[`simple.md 3`] = `
This is a long long long long long long long long long long long long long long long paragraph.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This is a long long long long long long long long long long long long long long long paragraph.

`;

exports[`special-prefix.md 1`] = `
abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc - abc abc abc

Expand Down Expand Up @@ -186,6 +298,49 @@ abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc

`;

exports[`special-prefix.md 3`] = `
abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc - abc abc abc

## Supported Rules

- [no-disabled-tests](/packages/eslint-plugin-jest/docs/rules/no-disabled-tests.md) - disallow disabled tests.
- [no-focused-tests](/packages/eslint-plugin-jest/docs/rules/no-focused-tests.md) - disallow focused tests.
- [no-identical-title](/packages/eslint-plugin-jest/docs/rules/no-identical-title.md) - disallow identical titles.
- [valid-expect](/packages/eslint-plugin-jest/docs/rules/valid-expect.md) - ensure expect is called correctly.

## Supported Rules

* [no-disabled-tests](/packages/eslint-plugin-jest/docs/rules/no-disabled-tests.md)
- disallow disabled tests.
* [no-focused-tests](/packages/eslint-plugin-jest/docs/rules/no-focused-tests.md)
- disallow focused tests.
* [no-identical-title](/packages/eslint-plugin-jest/docs/rules/no-identical-title.md)
- disallow identical titles.
* [valid-expect](/packages/eslint-plugin-jest/docs/rules/valid-expect.md) -
ensure expect is called correctly.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc abc - abc abc abc

## Supported Rules

* [no-disabled-tests](/packages/eslint-plugin-jest/docs/rules/no-disabled-tests.md) - disallow disabled tests.
* [no-focused-tests](/packages/eslint-plugin-jest/docs/rules/no-focused-tests.md) - disallow focused tests.
* [no-identical-title](/packages/eslint-plugin-jest/docs/rules/no-identical-title.md) - disallow identical titles.
* [valid-expect](/packages/eslint-plugin-jest/docs/rules/valid-expect.md) - ensure expect is called correctly.

## Supported Rules

* [no-disabled-tests](/packages/eslint-plugin-jest/docs/rules/no-disabled-tests.md)
* disallow disabled tests.
* [no-focused-tests](/packages/eslint-plugin-jest/docs/rules/no-focused-tests.md)
* disallow focused tests.
* [no-identical-title](/packages/eslint-plugin-jest/docs/rules/no-identical-title.md)
* disallow identical titles.
* [valid-expect](/packages/eslint-plugin-jest/docs/rules/valid-expect.md) -
ensure expect is called correctly.

`;

exports[`whitespace.md 1`] = `
<!-- 0xA0 non-breaking whitespace -->

Expand Down Expand Up @@ -224,3 +379,22 @@ keep these words together keep these words together keep these words 
keep these words together keep these words together keep these words together keep these words together

`;

exports[`whitespace.md 3`] = `
<!-- 0xA0 non-breaking whitespace -->

keep these words together keep these words together keep these words together keep these words together

<!-- 0x20 standard whitespace -->

keep these words together keep these words together keep these words together keep these words together
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<!-- 0xA0 non-breaking whitespace -->

keep these words together keep these words together keep these words together keep these words together

<!-- 0x20 standard whitespace -->

keep these words together keep these words together keep these words together keep these words together

`;
3 changes: 2 additions & 1 deletion tests/markdown_paragraph/jsfmt.spec.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
run_spec(__dirname, { parser: "markdown" });
run_spec(__dirname, { parser: "markdown", proseWrap: false });
run_spec(__dirname, { parser: "markdown", proseWrap: "never" });
run_spec(__dirname, { parser: "markdown", proseWrap: "preserve" });
10 changes: 10 additions & 0 deletions tests/markdown_paragraph/lorem.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Hic dicta et recusandae incidunt. Reiciendis saepe voluptatem tempore rem aut.
Iusto sapiente impedit. Laudantium ut id non et aperiam ab.

Sit minus architecto quas quibusdam sed ipsam aut eum.
Dolores tempora reiciendis magni blanditiis laborum aliquid rem corporis enim. Et consectetur quo sed excepturi soluta repudiandae commodi id.
Eum possimus optio distinctio incidunt quasi optio culpa accusamus.
Architecto esse ut aut autem ullam consequatur reiciendis aliquid dolorum.

Et quam mollitia velit iste enim exercitationem nemo.
Hic dignissimos eos et. Eos eos consequatur.
3 changes: 2 additions & 1 deletion tests_config/run_spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,8 @@ function mergeDefaultOptions(parserConfig) {
return Object.assign(
{
parser: "flow",
printWidth: 80
printWidth: 80,
proseWrap: "always"
},
parserConfig
);
Expand Down