Skip to content

Commit e8cf6f6

Browse files
committed
Fix error with anchor not being assigned to an empty node
fix #301
1 parent a583097 commit e8cf6f6

File tree

3 files changed

+77
-45
lines changed

3 files changed

+77
-45
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4747
- Removed `bower.json`.
4848
- Tags are now url-decoded in `load()` and url-encoded in `dump()`
4949
(previously usage of custom non-ascii tags may have led to invalid YAML that can't be parsed).
50+
- Anchors now work correctly with empty nodes, #301.
5051

5152

5253
## [3.14.1] - 2020-12-07

lib/loader.js

Lines changed: 48 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1448,61 +1448,64 @@ function composeNode(state, parentIndent, nodeContext, allowToSeek, allowCompact
14481448
}
14491449
}
14501450

1451-
if (state.tag !== null && state.tag !== '!') {
1452-
if (state.tag === '?') {
1453-
// Implicit resolving is not allowed for non-scalar types, and '?'
1454-
// non-specific tag is only automatically assigned to plain scalars.
1455-
//
1456-
// We only need to check kind conformity in case user explicitly assigns '?'
1457-
// tag, for example like this: "!<?> [0]"
1458-
//
1459-
if (state.result !== null && state.kind !== 'scalar') {
1460-
throwError(state, 'unacceptable node kind for !<?> tag; it should be "scalar", not "' + state.kind + '"');
1461-
}
1451+
if (state.tag === null) {
1452+
if (state.anchor !== null) {
1453+
state.anchorMap[state.anchor] = state.result;
1454+
}
14621455

1463-
for (typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) {
1464-
type = state.implicitTypes[typeIndex];
1456+
} else if (state.tag === '?') {
1457+
// Implicit resolving is not allowed for non-scalar types, and '?'
1458+
// non-specific tag is only automatically assigned to plain scalars.
1459+
//
1460+
// We only need to check kind conformity in case user explicitly assigns '?'
1461+
// tag, for example like this: "!<?> [0]"
1462+
//
1463+
if (state.result !== null && state.kind !== 'scalar') {
1464+
throwError(state, 'unacceptable node kind for !<?> tag; it should be "scalar", not "' + state.kind + '"');
1465+
}
14651466

1466-
if (type.resolve(state.result)) { // `state.result` updated in resolver if matched
1467-
state.result = type.construct(state.result);
1468-
state.tag = type.tag;
1469-
if (state.anchor !== null) {
1470-
state.anchorMap[state.anchor] = state.result;
1471-
}
1472-
break;
1467+
for (typeIndex = 0, typeQuantity = state.implicitTypes.length; typeIndex < typeQuantity; typeIndex += 1) {
1468+
type = state.implicitTypes[typeIndex];
1469+
1470+
if (type.resolve(state.result)) { // `state.result` updated in resolver if matched
1471+
state.result = type.construct(state.result);
1472+
state.tag = type.tag;
1473+
if (state.anchor !== null) {
1474+
state.anchorMap[state.anchor] = state.result;
14731475
}
1476+
break;
14741477
}
1478+
}
1479+
} else if (state.tag !== '!') {
1480+
if (_hasOwnProperty.call(state.typeMap[state.kind || 'fallback'], state.tag)) {
1481+
type = state.typeMap[state.kind || 'fallback'][state.tag];
14751482
} else {
1476-
if (_hasOwnProperty.call(state.typeMap[state.kind || 'fallback'], state.tag)) {
1477-
type = state.typeMap[state.kind || 'fallback'][state.tag];
1478-
} else {
1479-
// looking for multi type
1480-
type = null;
1481-
typeList = state.typeMap.multi[state.kind || 'fallback'];
1482-
1483-
for (typeIndex = 0, typeQuantity = typeList.length; typeIndex < typeQuantity; typeIndex += 1) {
1484-
if (state.tag.slice(0, typeList[typeIndex].tag.length) === typeList[typeIndex].tag) {
1485-
type = typeList[typeIndex];
1486-
break;
1487-
}
1483+
// looking for multi type
1484+
type = null;
1485+
typeList = state.typeMap.multi[state.kind || 'fallback'];
1486+
1487+
for (typeIndex = 0, typeQuantity = typeList.length; typeIndex < typeQuantity; typeIndex += 1) {
1488+
if (state.tag.slice(0, typeList[typeIndex].tag.length) === typeList[typeIndex].tag) {
1489+
type = typeList[typeIndex];
1490+
break;
14881491
}
14891492
}
1493+
}
14901494

1491-
if (!type) {
1492-
throwError(state, 'unknown tag !<' + state.tag + '>');
1493-
}
1495+
if (!type) {
1496+
throwError(state, 'unknown tag !<' + state.tag + '>');
1497+
}
14941498

1495-
if (state.result !== null && type.kind !== state.kind) {
1496-
throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"');
1497-
}
1499+
if (state.result !== null && type.kind !== state.kind) {
1500+
throwError(state, 'unacceptable node kind for !<' + state.tag + '> tag; it should be "' + type.kind + '", not "' + state.kind + '"');
1501+
}
14981502

1499-
if (!type.resolve(state.result, state.tag)) { // `state.result` updated in resolver if matched
1500-
throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag');
1501-
} else {
1502-
state.result = type.construct(state.result, state.tag);
1503-
if (state.anchor !== null) {
1504-
state.anchorMap[state.anchor] = state.result;
1505-
}
1503+
if (!type.resolve(state.result, state.tag)) { // `state.result` updated in resolver if matched
1504+
throwError(state, 'cannot resolve a node with !<' + state.tag + '> explicit tag');
1505+
} else {
1506+
state.result = type.construct(state.result, state.tag);
1507+
if (state.anchor !== null) {
1508+
state.anchorMap[state.anchor] = state.result;
15061509
}
15071510
}
15081511
}

test/issues/0301.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
'use strict';
2+
3+
4+
const assert = require('assert');
5+
const yaml = require('../../');
6+
7+
8+
it('should assign anchor to an empty node', function () {
9+
assert.deepStrictEqual(
10+
yaml.load('foo: &a\nbar: *a\n'),
11+
{ foo: null, bar: null }
12+
);
13+
14+
assert.deepStrictEqual(
15+
yaml.load('{ foo: &a, bar: *a }'),
16+
{ foo: null, bar: null }
17+
);
18+
19+
assert.deepStrictEqual(
20+
yaml.load('- &a\n- *a\n'),
21+
[ null, null ]
22+
);
23+
24+
assert.deepStrictEqual(
25+
yaml.load('[ &a, *a ]'),
26+
[ null, null ]
27+
);
28+
});

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy