Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(yaml) Add support for inline sequences and mappings #2513

Merged
merged 8 commits into from
Apr 30, 2020
197 changes: 120 additions & 77 deletions src/languages/yaml.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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