js-yaml
js-yaml copied to clipboard
Can't tokenize alias as key without seperator
js-yaml: @3.7.0 Node v7.2.1 Windows 10 Pro
disclaimer: I'm not an expert on the YAML spec
the bug
":" is a valid character when defining anchors and using aliases.
It is valid to use aliases as keys.
":" is also used to denote a node.
This seems to cause a bug where you are unable to use aliases as keys unless you separate the alias from the ":" with whitespace.
Trailing ":"'s look like they're being included in the alias token by the while loop in loader.readAlias().
I don't know the code very well, but a fix might need some extra logic in loader.composeNode().
some tests
const tests = [
// working cases (space before `:`)
`
adjective: &adj stealthy!
*adj : box :)
`,
`
adjective: &adj: stealthy!
*adj: : box :)
`,
`
adjective: &: stealthy!
*: : box :)
`,
// broken cases (no space)
`
adjective: &adj stealthy!
*adj: box :)
`,
`
adjective: &adj: stealthy!
*adj:: box :)
`,
`
adjective: &: stealthy!
*:: box :)
`,
]
for ( const content of tests )
try{ console.log(require('js-yaml').load(content)) }
catch(e) { console.log(e) }
output
{ adjective: 'stealthy!', 'stealthy!': 'box :)' }
{ adjective: 'stealthy!', 'stealthy!': 'box :)' }
{ adjective: 'stealthy!', 'stealthy!': 'box :)' }
{ Error
at generateError (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:162:10)
at throwError (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:168:9)
at readAlias (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1244:5)
at composeNode (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1336:20)
at readBlockMapping (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1004:16)
at composeNode (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1327:12)
at readDocument (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1489:3)
at loadDocuments (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1545:5)
at Object.load (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1562:19)
at Object.<anonymous> (C:\Users\leigh\repos\puppet\test-site\data\yaml.js:31:25)
name: 'YAMLException',
reason: 'unidentified alias "adj:"',
mark:
Mark {
name: null,
buffer: '\n adjective: &adj stealthy!\n *adj: box :)\n \n\u0000',
position: 41,
line: 2,
column: 9 },
message: 'unidentified alias "adj:" at line 3, column 10:\n *adj: box :)\n ^' }
{ Error
at generateError (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:162:10)
at throwError (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:168:9)
at readAlias (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1244:5)
at composeNode (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1336:20)
at readBlockMapping (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1004:16)
at composeNode (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1327:12)
at readDocument (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1489:3)
at loadDocuments (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1545:5)
at Object.load (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1562:19)
at Object.<anonymous> (C:\Users\leigh\repos\puppet\test-site\data\yaml.js:31:25)
name: 'YAMLException',
reason: 'unidentified alias "adj::"',
mark:
Mark {
name: null,
buffer: '\n adjective: &adj: stealthy!\n *adj:: box :)\n \n\u0000',
position: 42,
line: 2,
column: 10 },
message: 'unidentified alias "adj::" at line 3, column 11:\n *adj:: box :)\n ^' }
{ Error
at generateError (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:162:10)
at throwError (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:168:9)
at readAlias (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1244:5)
at composeNode (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1336:20)
at readBlockMapping (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1004:16)
at composeNode (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1327:12)
at readDocument (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1489:3)
at loadDocuments (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1545:5)
at Object.load (C:\Users\leigh\repos\puppet\test-site\data\node_modules\js-yaml\lib\js-yaml\loader.js:1562:19)
at Object.<anonymous> (C:\Users\leigh\repos\puppet\test-site\data\yaml.js:31:25)
name: 'YAMLException',
reason: 'unidentified alias "::"',
mark:
Mark {
name: null,
buffer: '\n adjective: &: stealthy!\n *:: box :)\n \n\u0000',
position: 39,
line: 2,
column: 7 },
message: 'unidentified alias "::" at line 3, column 8:\n *:: box :)\n ^' }
This is an edge case. The spec is not very clear on that. @flyx mentioned that he had been asking about that on the mailing list two years ago: https://sourceforge.net/p/yaml/mailman/message/34909032/
I would generally add a space after an alias key to make sure it's portable. It should also be noted that libyaml and pyyaml do not support : anywhere in aliases/anchors.
When playing with that, it seems I found a bug in libyaml, pyyaml and snakeyaml:
foo: &a:b bar is parsed the same as foo: &a :b bar
So I would avoid : in aliases completely.
@perlpunk In personal experience, I have not seen other usage in which people add spaces after their aliases to mitigate this problem, but it's good advice for compat /w this version of js-yaml.
I agree about disallowing : in aliases in the tokenizer.
Since the spec is so lax on this point, it's probably a source of implementation specific divergences like you discovered.
Neat find!