diff --git a/lib/js-yaml/dumper.js b/lib/js-yaml/dumper.js index f3d4fd93..91efdf7e 100644 --- a/lib/js-yaml/dumper.js +++ b/lib/js-yaml/dumper.js @@ -280,24 +280,25 @@ function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, te var hasFoldableLine = false; // only checked if shouldTrackWidth var shouldTrackWidth = lineWidth !== -1; var previousLineBreak = -1; // count the first line correctly - var plain = isPlainSafeFirst(string.charCodeAt(0)) - && !isWhitespace(string.charCodeAt(string.length - 1)); + var plain = isPlainSafeFirst(string.codePointAt(0)) + && !isWhitespace(string.codePointAt(string.length - 1)); + var chars = Array.from(string); if (singleLineOnly) { // Case: no block styles. // Check for disallowed characters to rule out plain and single. - for (i = 0; i < string.length; i++) { - char = string.charCodeAt(i); + for (i = 0; i < chars.length; i++) { + char = chars[i].codePointAt(0); if (!isPrintable(char)) { return STYLE_DOUBLE; } - prev_char = i > 0 ? string.charCodeAt(i - 1) : null; + prev_char = i > 0 ? chars[i - 1].codePointAt(0) : null; plain = plain && isPlainSafe(char, prev_char); } } else { // Case: block styles permitted. - for (i = 0; i < string.length; i++) { - char = string.charCodeAt(i); + for (i = 0; i < chars.length; i++) { + char = chars[i].codePointAt(0); if (char === CHAR_LINE_FEED) { hasLineBreak = true; // Check if any line can be folded. @@ -311,7 +312,7 @@ function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, te } else if (!isPrintable(char)) { return STYLE_DOUBLE; } - prev_char = i > 0 ? string.charCodeAt(i - 1) : null; + prev_char = i > 0 ? chars[i - 1].codePointAt(0) : null; plain = plain && isPlainSafe(char, prev_char); } // in case the end is missing a \n @@ -489,24 +490,15 @@ function foldLine(line, width) { // Escapes a double-quoted string. function escapeString(string) { var result = ''; - var char, nextChar; + var char; var escapeSeq; - for (var i = 0; i < string.length; i++) { - char = string.charCodeAt(i); - // Check for surrogate pairs (reference Unicode 3.0 section "3.7 Surrogates"). - if (char >= 0xD800 && char <= 0xDBFF/* high surrogate */) { - nextChar = string.charCodeAt(i + 1); - if (nextChar >= 0xDC00 && nextChar <= 0xDFFF/* low surrogate */) { - // Combine the surrogate pair and store it escaped. - result += encodeHex((char - 0xD800) * 0x400 + nextChar - 0xDC00 + 0x10000); - // Advance index one extra since we already used that char here. - i++; continue; - } - } + var chars = Array.from(string); + for (var i = 0; i < chars.length; i++) { + char = chars[i].codePointAt(0); escapeSeq = ESCAPE_SEQUENCES[char]; result += !escapeSeq && isPrintable(char) - ? string[i] + ? chars[i] : escapeSeq || encodeHex(char); } diff --git a/test/issues/0369.js b/test/issues/0369.js deleted file mode 100644 index f96baac1..00000000 --- a/test/issues/0369.js +++ /dev/null @@ -1,11 +0,0 @@ -'use strict'; - - -var assert = require('assert'); -var yaml = require('../../'); - - -test('should dump astrals as codepoint', function () { - assert.deepEqual(yaml.safeDump('😀'), '"\\U0001F600"\n'); - assert.deepEqual(yaml.safeLoad('"\\U0001F600"'), '😀'); -}); diff --git a/test/issues/0587.js b/test/issues/0587.js new file mode 100644 index 00000000..3575d2d7 --- /dev/null +++ b/test/issues/0587.js @@ -0,0 +1,20 @@ +'use strict'; + + +var assert = require('assert'); +var yaml = require('../../'); + + +suite('Should not escape emojis', function () { + test('plain', function () { + assert.strictEqual(yaml.safeDump('😀'), '😀\n'); + }); + + test('escape \\ and " in double-quoted', function () { + assert.strictEqual(yaml.safeDump('\u0007 😀 escape\\ escaper"'), '"\\a 😀 escape\\\\ escaper\\""\n'); + }); + + test('load', function () { + assert.strictEqual(yaml.safeLoad('"\\U0001F600"'), '😀'); + }); +});