groovy.js (3876B)
1 /** 2 * @param {string} value 3 * @returns {RegExp} 4 * */ 5 6 /** 7 * @param {RegExp | string } re 8 * @returns {string} 9 */ 10 function source(re) { 11 if (!re) return null; 12 if (typeof re === "string") return re; 13 14 return re.source; 15 } 16 17 /** 18 * @param {RegExp | string } re 19 * @returns {string} 20 */ 21 function lookahead(re) { 22 return concat('(?=', re, ')'); 23 } 24 25 /** 26 * @param {...(RegExp | string) } args 27 * @returns {string} 28 */ 29 function concat(...args) { 30 const joined = args.map((x) => source(x)).join(""); 31 return joined; 32 } 33 34 /* 35 Language: Groovy 36 Author: Guillaume Laforge <glaforge@gmail.com> 37 Description: Groovy programming language implementation inspired from Vsevolod's Java mode 38 Website: https://groovy-lang.org 39 */ 40 41 function variants(variants, obj = {}) { 42 obj.variants = variants; 43 return obj; 44 } 45 46 function groovy(hljs) { 47 const IDENT_RE = '[A-Za-z0-9_$]+'; 48 const COMMENT = variants([ 49 hljs.C_LINE_COMMENT_MODE, 50 hljs.C_BLOCK_COMMENT_MODE, 51 hljs.COMMENT( 52 '/\\*\\*', 53 '\\*/', 54 { 55 relevance : 0, 56 contains : [ 57 { 58 // eat up @'s in emails to prevent them to be recognized as doctags 59 begin: /\w+@/, relevance: 0 60 }, { 61 className : 'doctag', 62 begin : '@[A-Za-z]+' 63 } 64 ] 65 } 66 ) 67 ]); 68 const REGEXP = { 69 className: 'regexp', 70 begin: /~?\/[^\/\n]+\//, 71 contains: [ 72 hljs.BACKSLASH_ESCAPE 73 ] 74 }; 75 const NUMBER = variants([ 76 hljs.BINARY_NUMBER_MODE, 77 hljs.C_NUMBER_MODE, 78 ]); 79 const STRING = variants([ 80 { 81 begin: /"""/, 82 end: /"""/ 83 }, { 84 begin: /'''/, 85 end: /'''/ 86 }, { 87 begin: "\\$/", 88 end: "/\\$", 89 relevance: 10 90 }, 91 hljs.APOS_STRING_MODE, 92 hljs.QUOTE_STRING_MODE, 93 ], 94 { className: "string" } 95 ); 96 97 return { 98 name: 'Groovy', 99 keywords: { 100 built_in: 'this super', 101 literal: 'true false null', 102 keyword: 103 'byte short char int long boolean float double void ' + 104 // groovy specific keywords 105 'def as in assert trait ' + 106 // common keywords with Java 107 'abstract static volatile transient public private protected synchronized final ' + 108 'class interface enum if else for while switch case break default continue ' + 109 'throw throws try catch finally implements extends new import package return instanceof' 110 }, 111 contains: [ 112 hljs.SHEBANG(), 113 COMMENT, 114 STRING, 115 REGEXP, 116 NUMBER, 117 { 118 className: 'class', 119 beginKeywords: 'class interface trait enum', end: '{', 120 illegal: ':', 121 contains: [ 122 {beginKeywords: 'extends implements'}, 123 hljs.UNDERSCORE_TITLE_MODE 124 ] 125 }, 126 { 127 className: 'meta', begin: '@[A-Za-z]+' 128 }, 129 { 130 // highlight map keys and named parameters as attrs 131 className: 'attr', begin: IDENT_RE + '[ \t]*:' 132 }, 133 { 134 // catch middle element of the ternary operator 135 // to avoid highlight it as a label, named parameter, or map key 136 begin: /\?/, 137 end: /:/, 138 contains: [ 139 COMMENT, 140 STRING, 141 REGEXP, 142 NUMBER, 143 'self' 144 ] 145 }, 146 { 147 // highlight labeled statements 148 className: 'symbol', 149 begin: '^[ \t]*' + lookahead(IDENT_RE + ':'), 150 excludeBegin: true, 151 end: IDENT_RE + ':', 152 relevance: 0 153 } 154 ], 155 illegal: /#|<\// 156 }; 157 } 158 159 module.exports = groovy;