Swap quotes (#355)
- During the first iteration, we printed the unescaped values which let to printing invalid JavaScript characters and bad things like invisible characters. - During the second iteration, we escaped everything, which generated valid JavaScript but you lost your emojis and chinese/cyrillic characters In this iteration, which I hope will be the last one, we maintain the string exactly as encoded and only swap quotes. The swap quotes implementation is a bit convoluted but I think it works.
This commit is contained in:
1 parent
d20a580655
commit
080b7f8ec4
4 files changed
+56
-23
No files matched your search
+46
-11
@@ -4,7 +4,6 @@ var comments = require("./comments");
|
||||
var FastPath = require("./fast-path");
|
||||
var util = require("./util");
|
||||
var isIdentifierName = require("esutils").keyword.isIdentifierNameES6;
|
||||
var jsesc = require("jsesc");
|
||||
|
||||
var docBuilders = require("./doc-builders");
|
||||
var concat = docBuilders.concat;
|
||||
@@ -2319,6 +2318,13 @@ function nodeStr(node, options) {
|
||||
const str = node.value;
|
||||
isString.assert(str);
|
||||
|
||||
// Workaround a bug in the Javascript version of the flow parser where
|
||||
// astral unicode characters like \uD801\uDC28 are incorrectly parsed as
|
||||
// a sequence of \uFFFD.
|
||||
if (options.parser === "flow" && str.indexOf("\uFFFD") !== -1) {
|
||||
return node.raw;
|
||||
}
|
||||
|
||||
const containsSingleQuote = str.indexOf("'") !== -1;
|
||||
const containsDoubleQuote = str.indexOf('"') !== -1;
|
||||
|
||||
@@ -2330,19 +2336,48 @@ function nodeStr(node, options) {
|
||||
shouldUseSingleQuote = true;
|
||||
}
|
||||
|
||||
const result = jsesc(str, {
|
||||
quotes: shouldUseSingleQuote ? "single" : "double",
|
||||
wrap: true
|
||||
});
|
||||
const raw = node.extra ? node.extra.raw : node.raw;
|
||||
const isSingleQuote = raw.charAt(0) === "'";
|
||||
|
||||
// Workaround a bug in the Javascript version of the flow parser where
|
||||
// astral unicode characters like \uD801\uDC28 are incorrectly parsed as
|
||||
// a sequence of \uFFFD.
|
||||
if (options.parser === "flow" && result.indexOf("\\uFFFD") !== -1) {
|
||||
return node.raw;
|
||||
if (isSingleQuote && shouldUseSingleQuote ||
|
||||
!isSingleQuote && !shouldUseSingleQuote) {
|
||||
return raw;
|
||||
}
|
||||
|
||||
return result;
|
||||
const nextQuote = shouldUseSingleQuote ? "'" : '"';
|
||||
|
||||
// When we change the outer quotes, we need to change the number of
|
||||
// backslash before. In order to know how many backslash to put,
|
||||
// I manually did the first few examples and extracted a general rule
|
||||
// out of it.
|
||||
//
|
||||
// shouldSwitch === true
|
||||
//
|
||||
// 3 -> 3 "\\\'" -> '\\\''
|
||||
// 2 -> 3 "\\'" -> '\\\''
|
||||
// 1 -> 1 "\'" -> '\''
|
||||
// 0 -> 1 "\'" -> '\''
|
||||
//
|
||||
// Rule: n -> Math.floor(n / 2) + 1
|
||||
//
|
||||
// shouldSwitch === false
|
||||
//
|
||||
// 3 -> 2 '\\\'' -> "\\'"
|
||||
// 1 -> 0 '\'' -> "'"
|
||||
//
|
||||
// Rule: n -> n - 1
|
||||
return nextQuote + raw.slice(1, -1)
|
||||
.replace(/\\*['"]/g, (match) => {
|
||||
const quote = match[match.length - 1];
|
||||
const shouldSwitch = quote === "'" && shouldUseSingleQuote ||
|
||||
quote === '"' && !shouldUseSingleQuote;
|
||||
const numBackslash = match.length - 1;
|
||||
const nextNumBackslash = shouldSwitch ?
|
||||
Math.floor(numBackslash / 2) + 1 :
|
||||
numBackslash - 1;
|
||||
|
||||
return '\\'.repeat(nextNumBackslash) + quote;
|
||||
}) + nextQuote;
|
||||
}
|
||||
|
||||
function isFirstStatement(path) {
|
||||
|
||||
@@ -57,11 +57,11 @@ exports[`test strings.js 1`] = `
|
||||
\"\'\";
|
||||
|
||||
\'\"\';
|
||||
\'\"\';
|
||||
\'\\\"\';
|
||||
\'\\\\\"\';
|
||||
|
||||
\"\'\";
|
||||
\"\'\";
|
||||
\"\\\'\";
|
||||
\"\\\\\'\";
|
||||
|
||||
\"\'\\\"\";
|
||||
@@ -71,7 +71,7 @@ exports[`test strings.js 1`] = `
|
||||
\"\\\\\";
|
||||
|
||||
\"\\0\";
|
||||
\"\\uD83D\\uDC36\";
|
||||
\"🐶\";
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -104,11 +104,11 @@ exports[`test strings.js 2`] = `
|
||||
\"\'\";
|
||||
|
||||
\'\"\';
|
||||
\'\"\';
|
||||
\'\\\"\';
|
||||
\'\\\\\"\';
|
||||
|
||||
\"\'\";
|
||||
\"\'\";
|
||||
\"\\\'\";
|
||||
\"\\\\\'\";
|
||||
|
||||
\'\\\'\"\';
|
||||
@@ -118,6 +118,6 @@ exports[`test strings.js 2`] = `
|
||||
\'\\\\\';
|
||||
|
||||
\'\\0\';
|
||||
\'\\uD83D\\uDC36\';
|
||||
\'🐶\';
|
||||
"
|
||||
`;
|
||||
@@ -30,17 +30,17 @@ exports[`test strings.js 1`] = `
|
||||
\"abc\",
|
||||
\"\'\",
|
||||
\'\"\',
|
||||
\'\"\',
|
||||
\'\\\"\',
|
||||
\'\\\\\"\',
|
||||
\"\'\",
|
||||
\"\'\",
|
||||
\"\\\'\",
|
||||
\"\\\\\'\",
|
||||
\"\'\\\"\",
|
||||
\"\'\\\"\",
|
||||
\"\\\\\",
|
||||
\"\\\\\",
|
||||
\"\\0\",
|
||||
\"\\uD83D\\uDC36\",
|
||||
\"🐶\",
|
||||
\'\\uD801\\uDC28\'
|
||||
];
|
||||
"
|
||||
|
||||
@@ -73,8 +73,6 @@ function utf16Length(str, pos) {
|
||||
exports[`test keys.js 1`] = `
|
||||
"({\'この事はつもり素晴らしいことさ\': \'35jL9V\'})
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
({
|
||||
\"\\u3053\\u306E\\u4E8B\\u306F\\u3064\\u3082\\u308A\\u7D20\\u6674\\u3089\\u3057\\u3044\\u3053\\u3068\\u3055\": \"35jL9V\"
|
||||
});
|
||||
({ \"この事はつもり素晴らしいことさ\": \"35jL9V\" });
|
||||
"
|
||||
`;
|
||||
Reference in new issue
Block a user