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:
Christopher Chedeau authored and GitHub committed 2017-01-20 14:47:52 -08:00
1 parent d20a580655
commit 080b7f8ec4
4 files changed
+56 -23

No files matched your search

+46 -11
View File
@@ -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\" });
"
`;