From 089c36efc56ac6c4b1224522bfff6c482e3a3536 Mon Sep 17 00:00:00 2001 From: Himura Kazuto Date: Tue, 16 Jun 2020 18:19:07 +0300 Subject: [PATCH 1/4] Introduce CHAR_BOM --- lib/js-yaml/dumper.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/js-yaml/dumper.js b/lib/js-yaml/dumper.js index f3d4fd93..995179f1 100644 --- a/lib/js-yaml/dumper.js +++ b/lib/js-yaml/dumper.js @@ -10,6 +10,7 @@ var DEFAULT_SAFE_SCHEMA = require('./schema/default_safe'); var _toString = Object.prototype.toString; var _hasOwnProperty = Object.prototype.hasOwnProperty; +var CHAR_BOM = 0xFEFF; var CHAR_TAB = 0x09; /* Tab */ var CHAR_LINE_FEED = 0x0A; /* LF */ var CHAR_CARRIAGE_RETURN = 0x0D; /* CR */ @@ -186,7 +187,7 @@ function isWhitespace(c) { function isPrintable(c) { return (0x00020 <= c && c <= 0x00007E) || ((0x000A1 <= c && c <= 0x00D7FF) && c !== 0x2028 && c !== 0x2029) - || ((0x0E000 <= c && c <= 0x00FFFD) && c !== 0xFEFF /* BOM */) + || ((0x0E000 <= c && c <= 0x00FFFD) && c !== CHAR_BOM) || (0x10000 <= c && c <= 0x10FFFF); } @@ -198,9 +199,8 @@ function isPrintable(c) { // [3] c-byte-order-mark ::= #xFEFF function isNsChar(c) { return isPrintable(c) && !isWhitespace(c) - // byte-order-mark - && c !== 0xFEFF - // b-char + && c !== CHAR_BOM + // - b-char && c !== CHAR_CARRIAGE_RETURN && c !== CHAR_LINE_FEED; } @@ -226,7 +226,8 @@ function isPlainSafe(c, prev) { function isPlainSafeFirst(c) { // Uses a subset of ns-char - c-indicator // where ns-char = nb-char - s-white. - return isPrintable(c) && c !== 0xFEFF + // No support of ( ( “?” | “:” | “-” ) /* Followed by an ns-plain-safe(c)) */ ) part + return isPrintable(c) && c !== CHAR_BOM && !isWhitespace(c) // - s-white // - (c-indicator ::= // “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}” From db3eb34fef32566da6feadabc4e9ab30a2985fa0 Mon Sep 17 00:00:00 2001 From: Himura Kazuto Date: Mon, 15 Jun 2020 15:54:36 +0300 Subject: [PATCH 2/4] Fix #521 test and add more useful cases --- test/issues/0521.js | 17 ++++++----------- test/issues/0521.yml | 4 ++-- 2 files changed, 8 insertions(+), 13 deletions(-) diff --git a/test/issues/0521.js b/test/issues/0521.js index a952c184..5f78087d 100644 --- a/test/issues/0521.js +++ b/test/issues/0521.js @@ -7,17 +7,12 @@ var readFileSync = require('fs').readFileSync; test('Don\'t quote strings with # without need', function () { - var data = yaml.safeLoad(readFileSync(require('path').join(__dirname, '/0521.yml'), 'utf8')); - - var sample = { - 'http://example.com/page#anchor': 'no#quotes#required', + var required = readFileSync(require('path').join(__dirname, '/0521.yml'), 'utf8'); + var data = { + 'http://example.com/page#anchor': 'no:quotes#required', 'parameter#fallback': 'quotes #required', - 'foo #bar': 'key is quoted' + 'quotes: required': 'Visit [link](http://example.com/foo#bar)' }; - - assert.deepEqual( - yaml.dump(sample), - yaml.dump(data) - ); - + var actual = yaml.safeDump(data); + assert.equal(actual, required); }); diff --git a/test/issues/0521.yml b/test/issues/0521.yml index 38e2505e..a7108c42 100644 --- a/test/issues/0521.yml +++ b/test/issues/0521.yml @@ -1,3 +1,3 @@ -http://example.com/page#anchor: no#quotes#required +http://example.com/page#anchor: no:quotes#required parameter#fallback: 'quotes #required' -'foo #bar': key is quoted +'quotes: required': Visit [link](http://example.com/foo#bar) From 5f26d3f56eba0f876d7bf5aba07a76616cd61928 Mon Sep 17 00:00:00 2001 From: Himura Kazuto Date: Tue, 16 Jun 2020 18:25:45 +0300 Subject: [PATCH 3/4] Improve Plain Style support --- lib/js-yaml/dumper.js | 65 ++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 26 deletions(-) diff --git a/lib/js-yaml/dumper.js b/lib/js-yaml/dumper.js index 995179f1..6686a920 100644 --- a/lib/js-yaml/dumper.js +++ b/lib/js-yaml/dumper.js @@ -194,32 +194,45 @@ function isPrintable(c) { // [34] ns-char ::= nb-char - s-white // [27] nb-char ::= c-printable - b-char - c-byte-order-mark // [26] b-char ::= b-line-feed | b-carriage-return -// [24] b-line-feed ::= #xA /* LF */ -// [25] b-carriage-return ::= #xD /* CR */ -// [3] c-byte-order-mark ::= #xFEFF -function isNsChar(c) { - return isPrintable(c) && !isWhitespace(c) - && c !== CHAR_BOM - // - b-char +// Including s-white (for some reason, examples doesn't match specs in this aspect) +// ns-char ::= c-printable - b-line-feed - b-carriage-return - c-byte-order-mark +function isNsCharOrWhitespace(c) { + return isPrintable(c) + && c !== CHAR_BOM + // - b-char && c !== CHAR_CARRIAGE_RETURN && c !== CHAR_LINE_FEED; } -// Simplified test for values allowed after the first character in plain style. -function isPlainSafe(c, prev) { - // Uses a subset of nb-char - c-flow-indicator - ":" - "#" - // where nb-char ::= c-printable - b-char - c-byte-order-mark. - return isPrintable(c) && c !== 0xFEFF - // - c-flow-indicator - && c !== CHAR_COMMA - && c !== CHAR_LEFT_SQUARE_BRACKET - && c !== CHAR_RIGHT_SQUARE_BRACKET - && c !== CHAR_LEFT_CURLY_BRACKET - && c !== CHAR_RIGHT_CURLY_BRACKET - // - ":" - "#" - // /* An ns-char preceding */ "#" - && c !== CHAR_COLON - && ((c !== CHAR_SHARP) || (prev && isNsChar(prev))); +// [127] ns-plain-safe(c) ::= c = flow-out ⇒ ns-plain-safe-out +// c = flow-in ⇒ ns-plain-safe-in +// c = block-key ⇒ ns-plain-safe-out +// c = flow-key ⇒ ns-plain-safe-in +// [128] ns-plain-safe-out ::= ns-char +// [129] ns-plain-safe-in ::= ns-char - c-flow-indicator +// [130] ns-plain-char(c) ::= ( ns-plain-safe(c) - “:” - “#” ) +// | ( /* An ns-char preceding */ “#” ) +// | ( “:” /* Followed by an ns-plain-safe(c) */ ) +function isPlainSafe(state, c, prev) { + var cIsNsCharOrWhitespace = isNsCharOrWhitespace(c); + var cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c); + return ( + // ns-plain-safe + state.flowLevel < 0 ? // c = flow-in + cIsNsCharOrWhitespace + : cIsNsCharOrWhitespace + // - c-flow-indicator + && c !== CHAR_COMMA + && c !== CHAR_LEFT_SQUARE_BRACKET + && c !== CHAR_RIGHT_SQUARE_BRACKET + && c !== CHAR_LEFT_CURLY_BRACKET + && c !== CHAR_RIGHT_CURLY_BRACKET + ) + // ns-plain-char + && c !== CHAR_SHARP // false on '#' + && !(prev === CHAR_COLON && !cIsNsChar) // false on ': ' + || (isNsCharOrWhitespace(prev) && !isWhitespace(prev) && c === CHAR_SHARP) // change to true on '[^ ]#' + || (prev === CHAR_COLON && cIsNsChar); // change to true on ':[^ ]' } // Simplified test for values allowed as the first character in plain style. @@ -274,7 +287,7 @@ var STYLE_PLAIN = 1, // STYLE_PLAIN or STYLE_SINGLE => no \n are in the string. // STYLE_LITERAL => no lines are suitable for folding (or lineWidth is -1). // STYLE_FOLDED => a line > lineWidth and can be folded (and lineWidth != -1). -function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, testAmbiguousType) { +function chooseScalarStyle(state, string, singleLineOnly, indentPerLevel, lineWidth, testAmbiguousType) { var i; var char, prev_char; var hasLineBreak = false; @@ -293,7 +306,7 @@ function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, te return STYLE_DOUBLE; } prev_char = i > 0 ? string.charCodeAt(i - 1) : null; - plain = plain && isPlainSafe(char, prev_char); + plain = plain && isPlainSafe(state, char, prev_char); } } else { // Case: block styles permitted. @@ -313,7 +326,7 @@ function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, te return STYLE_DOUBLE; } prev_char = i > 0 ? string.charCodeAt(i - 1) : null; - plain = plain && isPlainSafe(char, prev_char); + plain = plain && isPlainSafe(state, char, prev_char); } // in case the end is missing a \n hasFoldableLine = hasFoldableLine || (shouldTrackWidth && @@ -373,7 +386,7 @@ function writeScalar(state, string, level, iskey) { return testImplicitResolving(state, string); } - switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth, testAmbiguity)) { + switch (chooseScalarStyle(state, string, singleLineOnly, state.indent, lineWidth, testAmbiguity)) { case STYLE_PLAIN: return string; case STYLE_SINGLE: From 674c35ce53644e29398daaf8f5d112b44a0ad896 Mon Sep 17 00:00:00 2001 From: Himura Kazuto Date: Wed, 17 Jun 2020 14:47:52 +0300 Subject: [PATCH 4/4] Add issue number to test files --- test/issues/{0521.js => 0521,557.js} | 2 +- test/issues/{0521.yml => 0521,557.yml} | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename test/issues/{0521.js => 0521,557.js} (95%) rename test/issues/{0521.yml => 0521,557.yml} (100%) diff --git a/test/issues/0521.js b/test/issues/0521,557.js similarity index 95% rename from test/issues/0521.js rename to test/issues/0521,557.js index 5f78087d..6fcc38dc 100644 --- a/test/issues/0521.js +++ b/test/issues/0521,557.js @@ -7,7 +7,7 @@ var readFileSync = require('fs').readFileSync; test('Don\'t quote strings with # without need', function () { - var required = readFileSync(require('path').join(__dirname, '/0521.yml'), 'utf8'); + var required = readFileSync(require('path').join(__dirname, '/0521,557.yml'), 'utf8'); var data = { 'http://example.com/page#anchor': 'no:quotes#required', 'parameter#fallback': 'quotes #required', diff --git a/test/issues/0521.yml b/test/issues/0521,557.yml similarity index 100% rename from test/issues/0521.yml rename to test/issues/0521,557.yml