yaml.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /*
  2. Language: YAML
  3. Description: Yet Another Markdown Language
  4. Author: Stefan Wienert <stwienert@gmail.com>
  5. Contributors: Carl Baxter <carl@cbax.tech>
  6. Requires: ruby.js
  7. Website: https://yaml.org
  8. Category: common, config
  9. */
  10. function yaml(hljs) {
  11. const LITERALS = 'true false yes no null';
  12. // YAML spec allows non-reserved URI characters in tags.
  13. const URI_CHARACTERS = '[\\w#;/?:@&=+$,.~*\'()[\\]]+';
  14. // Define keys as starting with a word character
  15. // ...containing word chars, spaces, colons, forward-slashes, hyphens and periods
  16. // ...and ending with a colon followed immediately by a space, tab or newline.
  17. // The YAML spec allows for much more than this, but this covers most use-cases.
  18. const KEY = {
  19. className: 'attr',
  20. variants: [
  21. { begin: '\\w[\\w :\\/.-]*:(?=[ \t]|$)' },
  22. { // double quoted keys
  23. begin: '"\\w[\\w :\\/.-]*":(?=[ \t]|$)' },
  24. { // single quoted keys
  25. begin: '\'\\w[\\w :\\/.-]*\':(?=[ \t]|$)' }
  26. ]
  27. };
  28. const TEMPLATE_VARIABLES = {
  29. className: 'template-variable',
  30. variants: [
  31. { // jinja templates Ansible
  32. begin: /\{\{/,
  33. end: /\}\}/
  34. },
  35. { // Ruby i18n
  36. begin: /%\{/,
  37. end: /\}/
  38. }
  39. ]
  40. };
  41. const STRING = {
  42. className: 'string',
  43. relevance: 0,
  44. variants: [
  45. {
  46. begin: /'/,
  47. end: /'/
  48. },
  49. {
  50. begin: /"/,
  51. end: /"/
  52. },
  53. { begin: /\S+/ }
  54. ],
  55. contains: [
  56. hljs.BACKSLASH_ESCAPE,
  57. TEMPLATE_VARIABLES
  58. ]
  59. };
  60. // Strings inside of value containers (objects) can't contain braces,
  61. // brackets, or commas
  62. const CONTAINER_STRING = hljs.inherit(STRING, { variants: [
  63. {
  64. begin: /'/,
  65. end: /'/
  66. },
  67. {
  68. begin: /"/,
  69. end: /"/
  70. },
  71. { begin: /[^\s,{}[\]]+/ }
  72. ] });
  73. const DATE_RE = '[0-9]{4}(-[0-9][0-9]){0,2}';
  74. const TIME_RE = '([Tt \\t][0-9][0-9]?(:[0-9][0-9]){2})?';
  75. const FRACTION_RE = '(\\.[0-9]*)?';
  76. const ZONE_RE = '([ \\t])*(Z|[-+][0-9][0-9]?(:[0-9][0-9])?)?';
  77. const TIMESTAMP = {
  78. className: 'number',
  79. begin: '\\b' + DATE_RE + TIME_RE + FRACTION_RE + ZONE_RE + '\\b'
  80. };
  81. const VALUE_CONTAINER = {
  82. end: ',',
  83. endsWithParent: true,
  84. excludeEnd: true,
  85. keywords: LITERALS,
  86. relevance: 0
  87. };
  88. const OBJECT = {
  89. begin: /\{/,
  90. end: /\}/,
  91. contains: [ VALUE_CONTAINER ],
  92. illegal: '\\n',
  93. relevance: 0
  94. };
  95. const ARRAY = {
  96. begin: '\\[',
  97. end: '\\]',
  98. contains: [ VALUE_CONTAINER ],
  99. illegal: '\\n',
  100. relevance: 0
  101. };
  102. const MODES = [
  103. KEY,
  104. {
  105. className: 'meta',
  106. begin: '^---\\s*$',
  107. relevance: 10
  108. },
  109. { // multi line string
  110. // Blocks start with a | or > followed by a newline
  111. //
  112. // Indentation of subsequent lines must be the same to
  113. // be considered part of the block
  114. className: 'string',
  115. begin: '[\\|>]([1-9]?[+-])?[ ]*\\n( +)[^ ][^\\n]*\\n(\\2[^\\n]+\\n?)*'
  116. },
  117. { // Ruby/Rails erb
  118. begin: '<%[%=-]?',
  119. end: '[%-]?%>',
  120. subLanguage: 'ruby',
  121. excludeBegin: true,
  122. excludeEnd: true,
  123. relevance: 0
  124. },
  125. { // named tags
  126. className: 'type',
  127. begin: '!\\w+!' + URI_CHARACTERS
  128. },
  129. // https://yaml.org/spec/1.2/spec.html#id2784064
  130. { // verbatim tags
  131. className: 'type',
  132. begin: '!<' + URI_CHARACTERS + ">"
  133. },
  134. { // primary tags
  135. className: 'type',
  136. begin: '!' + URI_CHARACTERS
  137. },
  138. { // secondary tags
  139. className: 'type',
  140. begin: '!!' + URI_CHARACTERS
  141. },
  142. { // fragment id &ref
  143. className: 'meta',
  144. begin: '&' + hljs.UNDERSCORE_IDENT_RE + '$'
  145. },
  146. { // fragment reference *ref
  147. className: 'meta',
  148. begin: '\\*' + hljs.UNDERSCORE_IDENT_RE + '$'
  149. },
  150. { // array listing
  151. className: 'bullet',
  152. // TODO: remove |$ hack when we have proper look-ahead support
  153. begin: '-(?=[ ]|$)',
  154. relevance: 0
  155. },
  156. hljs.HASH_COMMENT_MODE,
  157. {
  158. beginKeywords: LITERALS,
  159. keywords: { literal: LITERALS }
  160. },
  161. TIMESTAMP,
  162. // numbers are any valid C-style number that
  163. // sit isolated from other words
  164. {
  165. className: 'number',
  166. begin: hljs.C_NUMBER_RE + '\\b',
  167. relevance: 0
  168. },
  169. OBJECT,
  170. ARRAY,
  171. STRING
  172. ];
  173. const VALUE_MODES = [ ...MODES ];
  174. VALUE_MODES.pop();
  175. VALUE_MODES.push(CONTAINER_STRING);
  176. VALUE_CONTAINER.contains = VALUE_MODES;
  177. return {
  178. name: 'YAML',
  179. case_insensitive: true,
  180. aliases: [ 'yml' ],
  181. contains: MODES
  182. };
  183. }
  184. module.exports = yaml;