From db3f52985ba6f3076e6fb4318ca0c5c3c578ccba Mon Sep 17 00:00:00 2001 From: Alex Kocharin Date: Thu, 10 Dec 2020 16:14:04 +0300 Subject: [PATCH] Don't quote literals with `:` except when necessary fix https://github.com/nodeca/js-yaml/issues/470 --- CHANGELOG.md | 1 + lib/dumper.js | 22 +++++++++++++++++----- test/issues/0470.js | 25 +++++++++++++++++++++++++ 3 files changed, 43 insertions(+), 5 deletions(-) create mode 100644 test/issues/0470.js diff --git a/CHANGELOG.md b/CHANGELOG.md index c58e3778..02136ea1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Reduced nesting of `/lib` folder. - Parse numbers according to YAML 1.2 instead of YAML 1.1 (`01234` is now decimal, `0o1234` is octal, `1:23` is parsed as string instead of base60). +- `dump()` no longer quotes `:` except when necessary, #470. ### Added - Added `.mjs` (es modules) support. diff --git a/lib/dumper.js b/lib/dumper.js index 4d2226dd..ffffe5d9 100644 --- a/lib/dumper.js +++ b/lib/dumper.js @@ -57,6 +57,8 @@ var DEPRECATED_BOOLEANS_SYNTAX = [ 'n', 'N', 'no', 'No', 'NO', 'off', 'Off', 'OFF' ]; +var DEPRECATED_BASE60_SYNTAX = /^[-+]?[0-9_]+(?::[0-9_]+)+(?:\.[0-9_]*)?$/; + function compileStyleMap(schema, map) { var result, keys, index, length, tag, style, type; @@ -221,10 +223,13 @@ function isPlainSafe(c, prev) { && 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))); + && ((c !== CHAR_SHARP) || (prev && isNsChar(prev))) + // - ":" + && ((c !== CHAR_COLON) || (prev && isNsChar(prev))) + // - but ": " isn't plain-safe + && !(prev && prev === CHAR_COLON && !isNsChar(c)); } // Simplified test for values allowed as the first character in plain style. @@ -259,6 +264,12 @@ function isPlainSafeFirst(c) { && c !== CHAR_GRAVE_ACCENT; } +// Simplified test for values allowed as the last character in plain style. +function isPlainSafeLast(c) { + // just not whitespace or colon, it will be checked to be plain character later + return !isWhitespace(c) && c !== CHAR_COLON; +} + // Same as 'string'.codePointAt(pos), but works in older browsers. function codePointAt(string, pos) { var first = string.charCodeAt(pos), second; @@ -302,7 +313,7 @@ function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth, var shouldTrackWidth = lineWidth !== -1; var previousLineBreak = -1; // count the first line correctly var plain = isPlainSafeFirst(codePointAt(string, 0)) - && !isWhitespace(codePointAt(string, string.length - 1)); + && isPlainSafeLast(codePointAt(string, string.length - 1)); if (singleLineOnly || forceQuotes) { // Case: no block styles. @@ -375,7 +386,8 @@ function writeScalar(state, string, level, iskey) { return state.quotingType === QUOTING_TYPE_DOUBLE ? '""' : "''"; } if (!state.noCompatMode && - DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1) { + DEPRECATED_BOOLEANS_SYNTAX.indexOf(string) !== -1 || + DEPRECATED_BASE60_SYNTAX.test(string)) { return state.quotingType === QUOTING_TYPE_DOUBLE ? ('"' + string + '"') : ("'" + string + "'"); } diff --git a/test/issues/0470.js b/test/issues/0470.js new file mode 100644 index 00000000..80045c8c --- /dev/null +++ b/test/issues/0470.js @@ -0,0 +1,25 @@ +'use strict'; + + +var assert = require('assert'); +var yaml = require('../../'); + + +it('Don\'t quote strings with : without need', function () { + var data = { + // no quotes needed + 'http://example.com': 'http://example.com', + // quotes required + 'foo: bar': 'foo: bar', + 'foo:': 'foo:' + }; + + var expected = ` +http://example.com: http://example.com +'foo: bar': 'foo: bar' +'foo:': 'foo:' +`.replace(/^\n/, ''); + + assert.strictEqual(yaml.dump(data), expected); + assert.deepStrictEqual(yaml.load(expected), data); +});