Add an option to print single quotes in JSX (#4798)
* feat(option-singleQuote-jsx): Added jsSingleQuote * feat(option-singleQuote-jsx): Refactored to use a simple jsxSingleQuote flag * feat(option-singleQuote-jsx): Fixed borked rebase * feat(option-singleQuote-jsx): Updated snapshots * feat(option-singleQuote-jsx): Resolved pending comments * feat(option-singleQuote-jsx): Removed assert * Fixed merge conflicts * Updated snapshots after merge conflictsmaster
parent
f6a95dd2e0
commit
e17512adcd
|
@ -60,7 +60,7 @@ Use single quotes instead of double quotes.
|
|||
|
||||
Notes:
|
||||
|
||||
- Quotes in JSX will always be double and ignore this setting.
|
||||
- JSX quotes ignore this option – see [jsx-single-quote](#jsx-single-quote).
|
||||
- If the number of quotes outweighs the other quote, the quote which is less used will be used to format the string - Example: `"I'm double quoted"` results in `"I'm double quoted"` and `"This \"example\" is single quoted"` results in `'This "example" is single quoted'`.
|
||||
|
||||
See the [strings rationale](rationale.md#strings) for more information.
|
||||
|
@ -69,6 +69,14 @@ See the [strings rationale](rationale.md#strings) for more information.
|
|||
| ------- | ---------------- | --------------------- |
|
||||
| `false` | `--single-quote` | `singleQuote: <bool>` |
|
||||
|
||||
## JSX Quotes
|
||||
|
||||
Use single quotes instead of double quotes in JSX.
|
||||
|
||||
| Default | CLI Override | API Override |
|
||||
| ------- | -------------------- | ------------------------ |
|
||||
| `false` | `--jsx-single-quote` | `jsxSingleQuote: <bool>` |
|
||||
|
||||
## Trailing Commas
|
||||
|
||||
Print trailing commas wherever possible when multi-line. (A single-line array, for example, never gets trailing commas.)
|
||||
|
|
|
@ -430,7 +430,7 @@ function getIndentSize(value, tabWidth) {
|
|||
);
|
||||
}
|
||||
|
||||
function printString(raw, options, isDirectiveLiteral) {
|
||||
function getPreferredQuote(raw, preferredQuote) {
|
||||
// `rawContent` is the string exactly like it appeared in the input source
|
||||
// code, without its enclosing quotes.
|
||||
const rawContent = raw.slice(1, -1);
|
||||
|
@ -438,17 +438,14 @@ function printString(raw, options, isDirectiveLiteral) {
|
|||
const double = { quote: '"', regex: /"/g };
|
||||
const single = { quote: "'", regex: /'/g };
|
||||
|
||||
const preferred = options.singleQuote ? single : double;
|
||||
const preferred = preferredQuote === "'" ? single : double;
|
||||
const alternate = preferred === single ? double : single;
|
||||
|
||||
let shouldUseAlternateQuote = false;
|
||||
let canChangeDirectiveQuotes = false;
|
||||
let result = preferred.quote;
|
||||
|
||||
// If `rawContent` contains at least one of the quote preferred for enclosing
|
||||
// the string, we might want to enclose with the alternate quote instead, to
|
||||
// minimize the number of escaped quotes.
|
||||
// Also check for the alternate quote, to determine if we're allowed to swap
|
||||
// the quotes on a DirectiveLiteral.
|
||||
if (
|
||||
rawContent.includes(preferred.quote) ||
|
||||
rawContent.includes(alternate.quote)
|
||||
|
@ -456,19 +453,31 @@ function printString(raw, options, isDirectiveLiteral) {
|
|||
const numPreferredQuotes = (rawContent.match(preferred.regex) || []).length;
|
||||
const numAlternateQuotes = (rawContent.match(alternate.regex) || []).length;
|
||||
|
||||
shouldUseAlternateQuote = numPreferredQuotes > numAlternateQuotes;
|
||||
} else {
|
||||
canChangeDirectiveQuotes = true;
|
||||
result =
|
||||
numPreferredQuotes > numAlternateQuotes
|
||||
? alternate.quote
|
||||
: preferred.quote;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
function printString(raw, options, isDirectiveLiteral) {
|
||||
// `rawContent` is the string exactly like it appeared in the input source
|
||||
// code, without its enclosing quotes.
|
||||
const rawContent = raw.slice(1, -1);
|
||||
|
||||
// Check for the alternate quote, to determine if we're allowed to swap
|
||||
// the quotes on a DirectiveLiteral.
|
||||
const canChangeDirectiveQuotes =
|
||||
!rawContent.includes('"') && !rawContent.includes("'");
|
||||
|
||||
const enclosingQuote =
|
||||
options.parser === "json"
|
||||
? double.quote
|
||||
? '"'
|
||||
: options.__isInHtmlAttribute
|
||||
? single.quote
|
||||
: shouldUseAlternateQuote
|
||||
? alternate.quote
|
||||
: preferred.quote;
|
||||
? "'"
|
||||
: getPreferredQuote(raw, options.singleQuote ? "'" : '"');
|
||||
|
||||
// Directives are exact code unit sequences, which means that you can't
|
||||
// change the escape sequences they use.
|
||||
|
@ -691,6 +700,7 @@ module.exports = {
|
|||
startsWithNoLookaheadToken,
|
||||
getAlignmentSize,
|
||||
getIndentSize,
|
||||
getPreferredQuote,
|
||||
printString,
|
||||
printNumber,
|
||||
hasIgnoreComment,
|
||||
|
|
|
@ -41,6 +41,13 @@ module.exports = {
|
|||
"Do not print semicolons, except at the beginning of lines which may need them."
|
||||
},
|
||||
singleQuote: commonOptions.singleQuote,
|
||||
jsxSingleQuote: {
|
||||
since: "1.15.0",
|
||||
category: CATEGORY_JAVASCRIPT,
|
||||
type: "boolean",
|
||||
default: false,
|
||||
description: "Use single quotes in JSX."
|
||||
},
|
||||
trailingComma: {
|
||||
since: "0.0.0",
|
||||
category: CATEGORY_JAVASCRIPT,
|
||||
|
|
|
@ -20,7 +20,8 @@ const {
|
|||
getPenultimate,
|
||||
startsWithNoLookaheadToken,
|
||||
getIndentSize,
|
||||
matchAncestorTypes
|
||||
matchAncestorTypes,
|
||||
getPreferredQuote
|
||||
} = require("../common/util");
|
||||
const {
|
||||
isNextLineEmpty,
|
||||
|
@ -33,8 +34,8 @@ const clean = require("./clean");
|
|||
const insertPragma = require("./pragma").insertPragma;
|
||||
const handleComments = require("./comments");
|
||||
const pathNeedsParens = require("./needs-parens");
|
||||
const preprocess = require("./preprocess");
|
||||
const { printHtmlBinding } = require("./html-binding");
|
||||
const preprocess = require("./preprocess");
|
||||
const {
|
||||
hasNode,
|
||||
hasFlowAnnotationComment,
|
||||
|
@ -1948,8 +1949,16 @@ function printPathNoParens(path, options, print, args) {
|
|||
if (n.value) {
|
||||
let res;
|
||||
if (isStringLiteral(n.value)) {
|
||||
const value = rawText(n.value);
|
||||
res = '"' + value.slice(1, -1).replace(/"/g, """) + '"';
|
||||
const raw = rawText(n.value);
|
||||
// Unescape all quotes so we get an accurate preferred quote
|
||||
let final = raw.replace(/'/g, "'").replace(/"/g, '"');
|
||||
const quote = getPreferredQuote(
|
||||
final,
|
||||
options.jsxSingleQuote ? "'" : '"'
|
||||
);
|
||||
const escape = quote === "'" ? "'" : """;
|
||||
final = final.slice(1, -1).replace(new RegExp(quote, "g"), escape);
|
||||
res = concat([quote, final, quote]);
|
||||
} else {
|
||||
res = path.call(print, "value");
|
||||
}
|
||||
|
@ -5257,7 +5266,7 @@ function printJSXElement(path, options, print) {
|
|||
containsMultipleAttributes ||
|
||||
containsMultipleExpressions;
|
||||
|
||||
const rawJsxWhitespace = options.singleQuote ? "{' '}" : '{" "}';
|
||||
const rawJsxWhitespace = options.jsxSingleQuote ? "{' '}" : '{" "}';
|
||||
const jsxWhitespace = ifBreak(concat([rawJsxWhitespace, softline]), " ");
|
||||
|
||||
const isFacebookTranslationTag =
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1 +1,16 @@
|
|||
run_spec(__dirname, ["flow", "babylon", "typescript"]);
|
||||
run_spec(__dirname, ["flow", "babylon", "typescript"], {
|
||||
singleQuote: false,
|
||||
jsxSingleQuote: false
|
||||
});
|
||||
run_spec(__dirname, ["flow", "babylon", "typescript"], {
|
||||
singleQuote: false,
|
||||
jsxSingleQuote: true
|
||||
});
|
||||
run_spec(__dirname, ["flow", "babylon", "typescript"], {
|
||||
singleQuote: true,
|
||||
jsxSingleQuote: false
|
||||
});
|
||||
run_spec(__dirname, ["flow", "babylon", "typescript"], {
|
||||
singleQuote: true,
|
||||
jsxSingleQuote: true
|
||||
});
|
||||
|
|
|
@ -1,3 +1,36 @@
|
|||
<div id=""'<>&quot;" />;
|
||||
<div id='"'<>&quot;' />;
|
||||
<div id={'\'""<>&quot;'} />;
|
||||
<div id='123' />;
|
||||
<div id=''"' />;
|
||||
<div id={'\'\"\\\''} />;
|
||||
<div
|
||||
single='foo'
|
||||
single2={'foo'}
|
||||
|
||||
double="bar"
|
||||
double2={"bar"}
|
||||
|
||||
singleDouble='"'
|
||||
singleDouble2={'"'}
|
||||
|
||||
doubleSingle="'"
|
||||
doubleSingle2={"'"}
|
||||
|
||||
singleEscaped={'\''}
|
||||
singleEscaped2='''
|
||||
|
||||
doubleEscaped={"\""}
|
||||
doubleEscaped2="""
|
||||
|
||||
singleBothEscaped={'\'"'}
|
||||
singleBothEscaped2=''"'
|
||||
|
||||
singleBoth='' "'
|
||||
singleBoth2={'\' "'}
|
||||
singleBoth3='' ' "'
|
||||
|
||||
doubleBoth="" '"
|
||||
doubleBoth2={"\" '"}
|
||||
doubleBoth3="" ' '"
|
||||
/>;
|
||||
|
|
|
@ -65,6 +65,8 @@ Format options:
|
|||
Defaults to css.
|
||||
--jsx-bracket-same-line Put > on the last line instead of at a new line.
|
||||
Defaults to false.
|
||||
--jsx-single-quote Use single quotes in JSX.
|
||||
Defaults to false.
|
||||
--parser <flow|babylon|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular>
|
||||
Which parser to use.
|
||||
--print-width <int> The line length where Prettier will try wrap.
|
||||
|
@ -206,6 +208,8 @@ Format options:
|
|||
Defaults to css.
|
||||
--jsx-bracket-same-line Put > on the last line instead of at a new line.
|
||||
Defaults to false.
|
||||
--jsx-single-quote Use single quotes in JSX.
|
||||
Defaults to false.
|
||||
--parser <flow|babylon|typescript|css|less|scss|json|json5|json-stringify|graphql|markdown|mdx|vue|yaml|html|angular>
|
||||
Which parser to use.
|
||||
--print-width <int> The line length where Prettier will try wrap.
|
||||
|
|
|
@ -196,6 +196,19 @@ Default: false
|
|||
|
||||
exports[`show detailed usage with --help jsx-bracket-same-line (write) 1`] = `Array []`;
|
||||
|
||||
exports[`show detailed usage with --help jsx-single-quote (stderr) 1`] = `""`;
|
||||
|
||||
exports[`show detailed usage with --help jsx-single-quote (stdout) 1`] = `
|
||||
"--jsx-single-quote
|
||||
|
||||
Use single quotes in JSX.
|
||||
|
||||
Default: false
|
||||
"
|
||||
`;
|
||||
|
||||
exports[`show detailed usage with --help jsx-single-quote (write) 1`] = `Array []`;
|
||||
|
||||
exports[`show detailed usage with --help list-different (stderr) 1`] = `""`;
|
||||
|
||||
exports[`show detailed usage with --help list-different (stdout) 1`] = `
|
||||
|
|
|
@ -82,6 +82,11 @@ This option cannot be used with --range-start and --range-end.",
|
|||
"description": "Put > on the last line instead of at a new line.",
|
||||
"type": "boolean",
|
||||
},
|
||||
"jsxSingleQuote": Object {
|
||||
"default": false,
|
||||
"description": "Use single quotes in JSX.",
|
||||
"type": "boolean",
|
||||
},
|
||||
"parser": Object {
|
||||
"default": undefined,
|
||||
"description": "Which parser to use.",
|
||||
|
|
|
@ -489,7 +489,7 @@ exports[`API getSupportInfo() with version 1.8.2 -> undefined 1`] = `
|
|||
\\"type\\": \\"boolean\\",
|
||||
},
|
||||
\\"cursorOffset\\": Object {
|
||||
@@ -56,10 +85,19 @@
|
||||
@@ -56,33 +85,61 @@
|
||||
},
|
||||
\\"filepath\\": Object {
|
||||
\\"default\\": undefined,
|
||||
|
@ -509,7 +509,17 @@ exports[`API getSupportInfo() with version 1.8.2 -> undefined 1`] = `
|
|||
\\"type\\": \\"boolean\\",
|
||||
},
|
||||
\\"jsxBracketSameLine\\": Object {
|
||||
@@ -73,16 +111,31 @@
|
||||
\\"default\\": false,
|
||||
\\"type\\": \\"boolean\\",
|
||||
},
|
||||
+ \\"jsxSingleQuote\\": Object {
|
||||
+ \\"default\\": false,
|
||||
+ \\"type\\": \\"boolean\\",
|
||||
+ },
|
||||
\\"parser\\": Object {
|
||||
\\"choices\\": Array [
|
||||
\\"flow\\",
|
||||
\\"babylon\\",
|
||||
\\"typescript\\",
|
||||
\\"css\\",
|
||||
\\"less\\",
|
||||
|
@ -542,7 +552,7 @@ exports[`API getSupportInfo() with version 1.8.2 -> undefined 1`] = `
|
|||
\\"range\\": Object {
|
||||
\\"end\\": Infinity,
|
||||
\\"start\\": 0,
|
||||
@@ -90,14 +143,15 @@
|
||||
@@ -90,14 +147,15 @@
|
||||
},
|
||||
\\"type\\": \\"int\\",
|
||||
},
|
||||
|
@ -1019,6 +1029,15 @@ exports[`CLI --support-info (stdout) 1`] = `
|
|||
\\"since\\": \\"0.17.0\\",
|
||||
\\"type\\": \\"boolean\\"
|
||||
},
|
||||
{
|
||||
\\"category\\": \\"JavaScript\\",
|
||||
\\"default\\": false,
|
||||
\\"description\\": \\"Use single quotes in JSX.\\",
|
||||
\\"name\\": \\"jsxSingleQuote\\",
|
||||
\\"pluginDefaults\\": {},
|
||||
\\"since\\": \\"1.15.0\\",
|
||||
\\"type\\": \\"boolean\\"
|
||||
},
|
||||
{
|
||||
\\"category\\": \\"Global\\",
|
||||
\\"choices\\": [
|
||||
|
|
Loading…
Reference in New Issue