Refactor and use getPreferredQuote in both jsx and handlebars printers (#11569)
* raw => rawContent
* Refactor getPreferredQuote
Exposing { quote, regex, escaped } from the getPreferredQuote return
value allows us to simplify a bit the code in the printer.
* Use the common/util function
And remove chooseEnclosingQuote
* Move favoriteQuote
* Fix lint
* Remove enclosing quotes _before_ unescape
This commit is contained in:
1 parent
737d436a95
commit
2f9663b6fa
3 files changed
+31
-57
No files matched your search
+10
-16
@@ -343,24 +343,21 @@ function getIndentSize(value, tabWidth) {
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} raw
|
||||
* @param {string} rawContent
|
||||
* @param {Quote} preferredQuote
|
||||
* @returns {Quote}
|
||||
* @returns {{ quote: Quote, regex: RegExp, escaped: string }}
|
||||
*/
|
||||
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);
|
||||
|
||||
/** @type {{ quote: '"', regex: RegExp }} */
|
||||
const double = { quote: '"', regex: /"/g };
|
||||
/** @type {{ quote: "'", regex: RegExp }} */
|
||||
const single = { quote: "'", regex: /'/g };
|
||||
function getPreferredQuote(rawContent, preferredQuote) {
|
||||
/** @type {{ quote: '"', regex: RegExp, escaped: """ }} */
|
||||
const double = { quote: '"', regex: /"/g, escaped: """ };
|
||||
/** @type {{ quote: "'", regex: RegExp, escaped: "'" }} */
|
||||
const single = { quote: "'", regex: /'/g, escaped: "'" };
|
||||
|
||||
const preferred = preferredQuote === "'" ? single : double;
|
||||
const alternate = preferred === single ? double : single;
|
||||
|
||||
let result = preferred.quote;
|
||||
let result = preferred;
|
||||
|
||||
// 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
|
||||
@@ -372,10 +369,7 @@ function getPreferredQuote(raw, preferredQuote) {
|
||||
const numPreferredQuotes = (rawContent.match(preferred.regex) || []).length;
|
||||
const numAlternateQuotes = (rawContent.match(alternate.regex) || []).length;
|
||||
|
||||
result =
|
||||
numPreferredQuotes > numAlternateQuotes
|
||||
? alternate.quote
|
||||
: preferred.quote;
|
||||
result = numPreferredQuotes > numAlternateQuotes ? alternate : preferred;
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -395,7 +389,7 @@ function printString(raw, options) {
|
||||
? '"'
|
||||
: options.__isInHtmlAttribute
|
||||
? "'"
|
||||
: getPreferredQuote(raw, options.singleQuote ? "'" : '"');
|
||||
: getPreferredQuote(rawContent, options.singleQuote ? "'" : '"').quote;
|
||||
|
||||
// It might sound unnecessary to use `makeString` even if the string already
|
||||
// is enclosed with `enclosingQuote`, but it isn't. The string could contain
|
||||
|
||||
@@ -14,7 +14,7 @@ const {
|
||||
},
|
||||
utils: { getDocParts, replaceTextEndOfLine },
|
||||
} = require("../document/index.js");
|
||||
const { isNonEmptyArray } = require("../common/util.js");
|
||||
const { getPreferredQuote, isNonEmptyArray } = require("../common/util.js");
|
||||
const { locStart, locEnd } = require("./loc.js");
|
||||
const clean = require("./clean.js");
|
||||
const {
|
||||
@@ -47,6 +47,8 @@ function print(path, options, print) {
|
||||
return options.originalText.slice(locStart(node), locEnd(node));
|
||||
}
|
||||
|
||||
const favoriteQuote = options.singleQuote ? "'" : '"';
|
||||
|
||||
switch (node.type) {
|
||||
case "Block":
|
||||
case "Program":
|
||||
@@ -153,14 +155,14 @@ function print(path, options, print) {
|
||||
// Let's assume quotes inside the content of text nodes are already
|
||||
// properly escaped with entities, otherwise the parse wouldn't have parsed them.
|
||||
const quote = isText
|
||||
? chooseEnclosingQuote(options, node.value.chars).quote
|
||||
? getPreferredQuote(node.value.chars, favoriteQuote).quote
|
||||
: node.value.type === "ConcatStatement"
|
||||
? chooseEnclosingQuote(
|
||||
options,
|
||||
? getPreferredQuote(
|
||||
node.value.parts
|
||||
.filter((part) => part.type === "TextNode")
|
||||
.map((part) => part.chars)
|
||||
.join("")
|
||||
.join(""),
|
||||
favoriteQuote
|
||||
).quote
|
||||
: "";
|
||||
|
||||
@@ -397,7 +399,7 @@ function print(path, options, print) {
|
||||
return ["<!--", node.value, "-->"];
|
||||
}
|
||||
case "StringLiteral": {
|
||||
return printStringLiteral(node.value, options);
|
||||
return printStringLiteral(node.value, favoriteQuote);
|
||||
}
|
||||
case "NumberLiteral": {
|
||||
return String(node.value);
|
||||
@@ -691,6 +693,8 @@ function generateHardlines(number = 0) {
|
||||
|
||||
/* StringLiteral print helpers */
|
||||
|
||||
/** @typedef {import("../common/util").Quote} Quote */
|
||||
|
||||
/**
|
||||
* Prints a string literal with the correct surrounding quotes based on
|
||||
* `options.singleQuote` and the number of escaped quotes contained in
|
||||
@@ -698,40 +702,13 @@ function generateHardlines(number = 0) {
|
||||
* in `common/util`, but has differences because of the way escaped characters
|
||||
* are treated in hbs string literals.
|
||||
* @param {string} stringLiteral - the string literal value
|
||||
* @param {object} options - the prettier options object
|
||||
* @param {Quote} favoriteQuote - the user's preferred quote: `'` or `"`
|
||||
*/
|
||||
function printStringLiteral(stringLiteral, options) {
|
||||
const { quote, regex } = chooseEnclosingQuote(options, stringLiteral);
|
||||
function printStringLiteral(stringLiteral, favoriteQuote) {
|
||||
const { quote, regex } = getPreferredQuote(stringLiteral, favoriteQuote);
|
||||
return [quote, stringLiteral.replace(regex, `\\${quote}`), quote];
|
||||
}
|
||||
|
||||
function chooseEnclosingQuote(options, stringLiteral) {
|
||||
const double = { quote: '"', regex: /"/g };
|
||||
const single = { quote: "'", regex: /'/g };
|
||||
|
||||
const preferred = options.singleQuote ? single : double;
|
||||
const alternate = preferred === single ? double : single;
|
||||
|
||||
let shouldUseAlternateQuote = false;
|
||||
|
||||
// If `stringLiteral` 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.
|
||||
if (
|
||||
stringLiteral.includes(preferred.quote) ||
|
||||
stringLiteral.includes(alternate.quote)
|
||||
) {
|
||||
const numPreferredQuotes = (stringLiteral.match(preferred.regex) || [])
|
||||
.length;
|
||||
const numAlternateQuotes = (stringLiteral.match(alternate.regex) || [])
|
||||
.length;
|
||||
|
||||
shouldUseAlternateQuote = numPreferredQuotes > numAlternateQuotes;
|
||||
}
|
||||
|
||||
return shouldUseAlternateQuote ? alternate : preferred;
|
||||
}
|
||||
|
||||
/* SubExpression print helpers */
|
||||
|
||||
function printSubExpressionPathAndParams(path, print) {
|
||||
|
||||
@@ -479,14 +479,17 @@ function printJsxAttribute(path, options, print) {
|
||||
let res;
|
||||
if (isStringLiteral(node.value)) {
|
||||
const raw = rawText(node.value);
|
||||
// Unescape all quotes so we get an accurate preferred quote
|
||||
let final = raw.replace(/'/g, "'").replace(/"/g, '"');
|
||||
const quote = getPreferredQuote(
|
||||
// Remove enclosing quotes and unescape
|
||||
// all quotes so we get an accurate preferred quote
|
||||
let final = raw
|
||||
.slice(1, -1)
|
||||
.replace(/'/g, "'")
|
||||
.replace(/"/g, '"');
|
||||
const { escaped, quote, regex } = getPreferredQuote(
|
||||
final,
|
||||
options.jsxSingleQuote ? "'" : '"'
|
||||
);
|
||||
const escape = quote === "'" ? "'" : """;
|
||||
final = final.slice(1, -1).replace(new RegExp(quote, "g"), escape);
|
||||
final = final.replace(regex, escaped);
|
||||
res = [quote, final, quote];
|
||||
} else {
|
||||
res = print("value");
|
||||
|
||||
Reference in new issue
Block a user