asciidoc.js 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. /**
  2. * @param {string} value
  3. * @returns {RegExp}
  4. * */
  5. /**
  6. * @param {RegExp | string } re
  7. * @returns {string}
  8. */
  9. function source(re) {
  10. if (!re) return null;
  11. if (typeof re === "string") return re;
  12. return re.source;
  13. }
  14. /**
  15. * @param {...(RegExp | string) } args
  16. * @returns {string}
  17. */
  18. function concat(...args) {
  19. const joined = args.map((x) => source(x)).join("");
  20. return joined;
  21. }
  22. /*
  23. Language: AsciiDoc
  24. Requires: xml.js
  25. Author: Dan Allen <dan.j.allen@gmail.com>
  26. Website: http://asciidoc.org
  27. Description: A semantic, text-based document format that can be exported to HTML, DocBook and other backends.
  28. Category: markup
  29. */
  30. /** @type LanguageFn */
  31. function asciidoc(hljs) {
  32. const HORIZONTAL_RULE = {
  33. begin: '^\'{3,}[ \\t]*$',
  34. relevance: 10
  35. };
  36. const ESCAPED_FORMATTING = [
  37. // escaped constrained formatting marks (i.e., \* \_ or \`)
  38. {
  39. begin: /\\[*_`]/
  40. },
  41. // escaped unconstrained formatting marks (i.e., \\** \\__ or \\``)
  42. // must ignore until the next formatting marks
  43. // this rule might not be 100% compliant with Asciidoctor 2.0 but we are entering undefined behavior territory...
  44. {
  45. begin: /\\\\\*{2}[^\n]*?\*{2}/
  46. },
  47. {
  48. begin: /\\\\_{2}[^\n]*_{2}/
  49. },
  50. {
  51. begin: /\\\\`{2}[^\n]*`{2}/
  52. },
  53. // guard: constrained formatting mark may not be preceded by ":", ";" or
  54. // "}". match these so the constrained rule doesn't see them
  55. {
  56. begin: /[:;}][*_`](?![*_`])/
  57. }
  58. ];
  59. const STRONG = [
  60. // inline unconstrained strong (single line)
  61. {
  62. className: 'strong',
  63. begin: /\*{2}([^\n]+?)\*{2}/
  64. },
  65. // inline unconstrained strong (multi-line)
  66. {
  67. className: 'strong',
  68. begin: concat(
  69. /\*\*/,
  70. /((\*(?!\*)|\\[^\n]|[^*\n\\])+\n)+/,
  71. /(\*(?!\*)|\\[^\n]|[^*\n\\])*/,
  72. /\*\*/
  73. ),
  74. relevance: 0
  75. },
  76. // inline constrained strong (single line)
  77. {
  78. className: 'strong',
  79. // must not precede or follow a word character
  80. begin: /\B\*(\S|\S[^\n]*?\S)\*(?!\w)/
  81. },
  82. // inline constrained strong (multi-line)
  83. {
  84. className: 'strong',
  85. // must not precede or follow a word character
  86. begin: /\*[^\s]([^\n]+\n)+([^\n]+)\*/
  87. }
  88. ];
  89. const EMPHASIS = [
  90. // inline unconstrained emphasis (single line)
  91. {
  92. className: 'emphasis',
  93. begin: /_{2}([^\n]+?)_{2}/
  94. },
  95. // inline unconstrained emphasis (multi-line)
  96. {
  97. className: 'emphasis',
  98. begin: concat(
  99. /__/,
  100. /((_(?!_)|\\[^\n]|[^_\n\\])+\n)+/,
  101. /(_(?!_)|\\[^\n]|[^_\n\\])*/,
  102. /__/
  103. ),
  104. relevance: 0
  105. },
  106. // inline constrained emphasis (single line)
  107. {
  108. className: 'emphasis',
  109. // must not precede or follow a word character
  110. begin: /\b_(\S|\S[^\n]*?\S)_(?!\w)/
  111. },
  112. // inline constrained emphasis (multi-line)
  113. {
  114. className: 'emphasis',
  115. // must not precede or follow a word character
  116. begin: /_[^\s]([^\n]+\n)+([^\n]+)_/
  117. },
  118. // inline constrained emphasis using single quote (legacy)
  119. {
  120. className: 'emphasis',
  121. // must not follow a word character or be followed by a single quote or space
  122. begin: '\\B\'(?![\'\\s])',
  123. end: '(\\n{2}|\')',
  124. // allow escaped single quote followed by word char
  125. contains: [{
  126. begin: '\\\\\'\\w',
  127. relevance: 0
  128. }],
  129. relevance: 0
  130. }
  131. ];
  132. const ADMONITION = {
  133. className: 'symbol',
  134. begin: '^(NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s+',
  135. relevance: 10
  136. };
  137. const BULLET_LIST = {
  138. className: 'bullet',
  139. begin: '^(\\*+|-+|\\.+|[^\\n]+?::)\\s+'
  140. };
  141. return {
  142. name: 'AsciiDoc',
  143. aliases: ['adoc'],
  144. contains: [
  145. // block comment
  146. hljs.COMMENT(
  147. '^/{4,}\\n',
  148. '\\n/{4,}$',
  149. // can also be done as...
  150. // '^/{4,}$',
  151. // '^/{4,}$',
  152. {
  153. relevance: 10
  154. }
  155. ),
  156. // line comment
  157. hljs.COMMENT(
  158. '^//',
  159. '$',
  160. {
  161. relevance: 0
  162. }
  163. ),
  164. // title
  165. {
  166. className: 'title',
  167. begin: '^\\.\\w.*$'
  168. },
  169. // example, admonition & sidebar blocks
  170. {
  171. begin: '^[=\\*]{4,}\\n',
  172. end: '\\n^[=\\*]{4,}$',
  173. relevance: 10
  174. },
  175. // headings
  176. {
  177. className: 'section',
  178. relevance: 10,
  179. variants: [
  180. {
  181. begin: '^(={1,6})[ \t].+?([ \t]\\1)?$'
  182. },
  183. {
  184. begin: '^[^\\[\\]\\n]+?\\n[=\\-~\\^\\+]{2,}$'
  185. }
  186. ]
  187. },
  188. // document attributes
  189. {
  190. className: 'meta',
  191. begin: '^:.+?:',
  192. end: '\\s',
  193. excludeEnd: true,
  194. relevance: 10
  195. },
  196. // block attributes
  197. {
  198. className: 'meta',
  199. begin: '^\\[.+?\\]$',
  200. relevance: 0
  201. },
  202. // quoteblocks
  203. {
  204. className: 'quote',
  205. begin: '^_{4,}\\n',
  206. end: '\\n_{4,}$',
  207. relevance: 10
  208. },
  209. // listing and literal blocks
  210. {
  211. className: 'code',
  212. begin: '^[\\-\\.]{4,}\\n',
  213. end: '\\n[\\-\\.]{4,}$',
  214. relevance: 10
  215. },
  216. // passthrough blocks
  217. {
  218. begin: '^\\+{4,}\\n',
  219. end: '\\n\\+{4,}$',
  220. contains: [{
  221. begin: '<',
  222. end: '>',
  223. subLanguage: 'xml',
  224. relevance: 0
  225. }],
  226. relevance: 10
  227. },
  228. BULLET_LIST,
  229. ADMONITION,
  230. ...ESCAPED_FORMATTING,
  231. ...STRONG,
  232. ...EMPHASIS,
  233. // inline smart quotes
  234. {
  235. className: 'string',
  236. variants: [
  237. {
  238. begin: "``.+?''"
  239. },
  240. {
  241. begin: "`.+?'"
  242. }
  243. ]
  244. },
  245. // inline unconstrained emphasis
  246. {
  247. className: 'code',
  248. begin: /`{2}/,
  249. end: /(\n{2}|`{2})/
  250. },
  251. // inline code snippets (TODO should get same treatment as strong and emphasis)
  252. {
  253. className: 'code',
  254. begin: '(`.+?`|\\+.+?\\+)',
  255. relevance: 0
  256. },
  257. // indented literal block
  258. {
  259. className: 'code',
  260. begin: '^[ \\t]',
  261. end: '$',
  262. relevance: 0
  263. },
  264. HORIZONTAL_RULE,
  265. // images and links
  266. {
  267. begin: '(link:)?(http|https|ftp|file|irc|image:?):\\S+?\\[[^[]*?\\]',
  268. returnBegin: true,
  269. contains: [
  270. {
  271. begin: '(link|image:?):',
  272. relevance: 0
  273. },
  274. {
  275. className: 'link',
  276. begin: '\\w',
  277. end: '[^\\[]+',
  278. relevance: 0
  279. },
  280. {
  281. className: 'string',
  282. begin: '\\[',
  283. end: '\\]',
  284. excludeBegin: true,
  285. excludeEnd: true,
  286. relevance: 0
  287. }
  288. ],
  289. relevance: 10
  290. }
  291. ]
  292. };
  293. }
  294. module.exports = asciidoc;