Skip to content

Commit

Permalink
Improve Plain Style support
Browse files Browse the repository at this point in the history
close #557
  • Loading branch information
Himura2la authored and rlidwka committed Dec 15, 2020
1 parent dc44dd3 commit 91f9662
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 40 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Expand Up @@ -19,7 +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.
- `dump()` no longer quotes `:`, `[`, `]`, `(`, `)` except when necessary, #470, #557.

### Added
- Added `.mjs` (es modules) support.
Expand Down
75 changes: 43 additions & 32 deletions lib/dumper.js
Expand Up @@ -9,6 +9,7 @@ var DEFAULT_SCHEMA = require('./schema/default');
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 */
Expand Down Expand Up @@ -193,50 +194,60 @@ 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);
}

// [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)
// byte-order-mark
&& c !== 0xFEFF
// 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_SHARP) || (prev && isNsChar(prev)))
// - ":"
&& ((c !== CHAR_COLON) || (prev && isNsChar(prev)))
// - but ": " isn't plain-safe
&& !(prev && prev === CHAR_COLON && !isNsChar(c));
// [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(c, prev, flowLevel) {
var cIsNsCharOrWhitespace = isNsCharOrWhitespace(c);
var cIsNsChar = cIsNsCharOrWhitespace && !isWhitespace(c);
return (
// ns-plain-safe
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.
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 ::=
// “-” | “?” | “:” | “,” | “[” | “]” | “{” | “}”
Expand Down Expand Up @@ -303,7 +314,7 @@ var STYLE_PLAIN = 1,
// 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, quotingType, forceQuotes) {
testAmbiguousType, quotingType, forceQuotes, flowLevel) {

var i;
var char = 0;
Expand All @@ -323,7 +334,7 @@ function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth,
if (!isPrintable(char)) {
return STYLE_DOUBLE;
}
plain = plain && isPlainSafe(char, prevChar);
plain = plain && isPlainSafe(char, prevChar, flowLevel);
prevChar = char;
}
} else {
Expand All @@ -343,7 +354,7 @@ function chooseScalarStyle(string, singleLineOnly, indentPerLevel, lineWidth,
} else if (!isPrintable(char)) {
return STYLE_DOUBLE;
}
plain = plain && isPlainSafe(char, prevChar);
plain = plain && isPlainSafe(char, prevChar, flowLevel);
prevChar = char;
}
// in case the end is missing a \n
Expand Down Expand Up @@ -411,7 +422,7 @@ function writeScalar(state, string, level, iskey) {
}

switch (chooseScalarStyle(string, singleLineOnly, state.indent, lineWidth,
testAmbiguity, state.quotingType, state.forceQuotes && !iskey)) {
testAmbiguity, state.quotingType, state.forceQuotes && !iskey, state.flowLevel)) {

case STYLE_PLAIN:
return string;
Expand Down
15 changes: 8 additions & 7 deletions test/issues/0521.js
Expand Up @@ -6,21 +6,22 @@ var yaml = require('../../');


it('Don\'t quote strings with # without need', function () {
var data = yaml.load(`
http://example.com/page#anchor: no#quotes#required
var required = `
http://example.com/page#anchor: no:quotes#required
parameter#fallback: 'quotes #required'
'quotes: required': Visit [link](http://example.com/foo#bar)
'foo #bar': key is quoted
`);
`.replace(/^\n/, '');

var sample = {
'http://example.com/page#anchor': 'no#quotes#required',
'http://example.com/page#anchor': 'no:quotes#required',
'parameter#fallback': 'quotes #required',
'quotes: required': 'Visit [link](http://example.com/foo#bar)',
'foo #bar': 'key is quoted'
};

assert.deepStrictEqual(
assert.strictEqual(
yaml.dump(sample),
yaml.dump(data)
required
);

});

0 comments on commit 91f9662

Please sign in to comment.