Skip to content

Commit

Permalink
(yaml) Add support for inline sequences and mappings (#2513)
Browse files Browse the repository at this point in the history
* Use containers to match inline sequences and mappings
* Add string type for inside inline elements
* Handle nested inline sequences and mappings
* Disallow all braces brackets and commas from strings inside inline mappings or sequences
* clean up implementation
* feed the linter

Co-authored-by: Josh Goebel <me@joshgoebel.com>
  • Loading branch information
pplantinga and joshgoebel authored Apr 30, 2020

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent a23f19e commit d98cd4f
Showing 3 changed files with 126 additions and 77 deletions.
197 changes: 120 additions & 77 deletions src/languages/yaml.js
Original file line number Diff line number Diff line change
@@ -11,7 +11,7 @@ export default function(hljs) {
var LITERALS = 'true false yes no null';

// YAML spec allows non-reserved URI characters in tags.
var URI_CHARACTERS = '[\\w#;/?:@&=+$,.~*\\\'()[\\]]+'
var URI_CHARACTERS = '[\\w#;/?:@&=+$,.~*\\\'()[\\]]+';

// Define keys as starting with a word character
// ...containing word chars, spaces, colons, forward-slashes, hyphens and periods
@@ -21,111 +21,154 @@ export default function(hljs) {
className: 'attr',
variants: [
{ begin: '\\w[\\w :\\/.-]*:(?=[ \t]|$)' },
{ begin: '"\\w[\\w :\\/.-]*":(?=[ \t]|$)' }, //double quoted keys
{ begin: '\'\\w[\\w :\\/.-]*\':(?=[ \t]|$)' } //single quoted keys
{ begin: '"\\w[\\w :\\/.-]*":(?=[ \t]|$)' }, // double quoted keys
{ begin: '\'\\w[\\w :\\/.-]*\':(?=[ \t]|$)' } // single quoted keys
]
};

var TEMPLATE_VARIABLES = {
className: 'template-variable',
variants: [
{ begin: '\{\{', end: '\}\}' }, // jinja templates Ansible
{ begin: '%\{', end: '\}' } // Ruby i18n
{ begin: '{{', end: '}}' }, // jinja templates Ansible
{ begin: '%{', end: '}' } // Ruby i18n
]
};
var STRING = {
className: 'string',
relevance: 0,
variants: [
{begin: /'/, end: /'/},
{begin: /"/, end: /"/},
{begin: /\S+/}
{ begin: /'/, end: /'/ },
{ begin: /"/, end: /"/ },
{ begin: /\S+/ }
],
contains: [
hljs.BACKSLASH_ESCAPE,
TEMPLATE_VARIABLES
]
};

// Strings inside of value containers (objects) can't contain braces,
// brackets, or commas
var CONTAINER_STRING = hljs.inherit(STRING, {
variants: [
{ begin: /'/, end: /'/ },
{ begin: /"/, end: /"/ },
{ begin: /[^\s,{}[\]]+/ }
]
});

var DATE_RE = '[0-9]{4}(-[0-9][0-9]){0,2}';
var TIME_RE = '([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?';
var FRACTION_RE = '(\\.[0-9]*)?';
var ZONE_RE = '([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?';
var TIMESTAMP = {
className: 'number',
begin: '\\b' + DATE_RE + TIME_RE + FRACTION_RE + ZONE_RE + '\\b',
}
begin: '\\b' + DATE_RE + TIME_RE + FRACTION_RE + ZONE_RE + '\\b'
};

var VALUE_CONTAINER = {
end: ',',
endsWithParent: true,
excludeEnd: true,
contains: [],
keywords: LITERALS,
relevance: 0
};
var OBJECT = {
begin: '{',
end: '}',
contains: [VALUE_CONTAINER],
illegal: '\\n',
relevance: 0
};
var ARRAY = {
begin: '\\[',
end: '\\]',
contains: [VALUE_CONTAINER],
illegal: '\\n',
relevance: 0
};

var MODES = [
KEY,
{
className: 'meta',
begin: '^---\s*$',
relevance: 10
},
{ // multi line string
// Blocks start with a | or > followed by a newline
//
// Indentation of subsequent lines must be the same to
// be considered part of the block
className: 'string',
begin: '[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*'
},
{ // Ruby/Rails erb
begin: '<%[%=-]?',
end: '[%-]?%>',
subLanguage: 'ruby',
excludeBegin: true,
excludeEnd: true,
relevance: 0
},
{ // named tags
className: 'type',
begin: '!\\w+!' + URI_CHARACTERS
},
// https://yaml.org/spec/1.2/spec.html#id2784064
{ // verbatim tags
className: 'type',
begin: '!<' + URI_CHARACTERS + ">"
},
{ // primary tags
className: 'type',
begin: '!' + URI_CHARACTERS
},
{ // secondary tags
className: 'type',
begin: '!!' + URI_CHARACTERS
},
{ // fragment id &ref
className: 'meta',
begin: '&' + hljs.UNDERSCORE_IDENT_RE + '$'
},
{ // fragment reference *ref
className: 'meta',
begin: '\\*' + hljs.UNDERSCORE_IDENT_RE + '$'
},
{ // array listing
className: 'bullet',
// TODO: remove |$ hack when we have proper look-ahead support
begin: '\\-(?=[ ]|$)',
relevance: 0
},
hljs.HASH_COMMENT_MODE,
{
beginKeywords: LITERALS,
keywords: { literal: LITERALS }
},
TIMESTAMP,
// numbers are any valid C-style number that
// sit isolated from other words
{
className: 'number',
begin: hljs.C_NUMBER_RE + '\\b'
},
OBJECT,
ARRAY,
STRING
];

var VALUE_MODES = [...MODES];
VALUE_MODES.pop();
VALUE_MODES.push(CONTAINER_STRING);
VALUE_CONTAINER.contains = VALUE_MODES;

return {
name: 'YAML',
case_insensitive: true,
aliases: ['yml', 'YAML'],
contains: [
KEY,
{
className: 'meta',
begin: '^---\s*$',
relevance: 10
},
{ // multi line string
// Blocks start with a | or > followed by a newline
//
// Indentation of subsequent lines must be the same to
// be considered part of the block
className: 'string',
begin: '[\\|>]([0-9]?[+-])?[ ]*\\n( *)[\\S ]+\\n(\\2[\\S ]+\\n?)*',
},
{ // Ruby/Rails erb
begin: '<%[%=-]?', end: '[%-]?%>',
subLanguage: 'ruby',
excludeBegin: true,
excludeEnd: true,
relevance: 0
},
{ // named tags
className: 'type',
begin: '!\\w+!' + URI_CHARACTERS,
},
// https://yaml.org/spec/1.2/spec.html#id2784064
{ // verbatim tags
className: 'type',
begin: '!<' + URI_CHARACTERS + ">",
},
{ // primary tags
className: 'type',
begin: '!' + URI_CHARACTERS,
},
{ // secondary tags
className: 'type',
begin: '!!' + URI_CHARACTERS,
},
{ // fragment id &ref
className: 'meta',
begin: '&' + hljs.UNDERSCORE_IDENT_RE + '$',
},
{ // fragment reference *ref
className: 'meta',
begin: '\\*' + hljs.UNDERSCORE_IDENT_RE + '$'
},
{ // array listing
className: 'bullet',
// TODO: remove |$ hack when we have proper look-ahead support
begin: '\\-(?=[ ]|$)',
relevance: 0
},
hljs.HASH_COMMENT_MODE,
{
beginKeywords: LITERALS,
keywords: {literal: LITERALS}
},
TIMESTAMP,
// numbers are any valid C-style number that
// sit isolated from other words
{
className: 'number',
begin: hljs.C_NUMBER_RE + '\\b'
},
STRING
]
contains: MODES
};
}
3 changes: 3 additions & 0 deletions test/markup/yaml/inline.expect.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<span class="hljs-attr">foo:</span> [<span class="hljs-string">bar</span>, <span class="hljs-string">bar2</span>, [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], <span class="hljs-number">3</span>]
<span class="hljs-attr">foo:</span> {<span class="hljs-attr">bar:</span> [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], <span class="hljs-attr">baz:</span> {<span class="hljs-attr">inside:</span> <span class="hljs-number">3</span>}}
<span class="hljs-attr">foo:</span> <span class="hljs-string">ba{}r,ba[]z</span>
3 changes: 3 additions & 0 deletions test/markup/yaml/inline.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
foo: [bar, bar2, [1, 2], 3]
foo: {bar: [1, 2], baz: {inside: 3}}
foo: ba{}r,ba[]z

0 comments on commit d98cd4f

Please sign in to comment.