api 사용안내 코드 강조 플러그인 추가(/publish/js/highlight)
@04aefabdee8d9757f17ae69c4877c2c0e55535c2
--- src/main/webapp/publish/api_guide.html
+++ src/main/webapp/publish/api_guide.html
... | ... | @@ -19,15 +19,16 @@ |
| 19 | 19 |
<script src="/publish/js/content.js"></script> |
| 20 | 20 |
<script src="/publish/js/allimtalk.js"></script> |
| 21 | 21 |
<script src="/publish/js/kakao_allimtalk.js"></script> |
| 22 |
- |
|
| 22 |
+ |
|
| 23 |
+ <!-- 플러그인 --> |
|
| 24 |
+ <script src="/publish/js/highlight/highlight.min.js"></script> |
|
| 25 |
+ <link rel="stylesheet" href="/publish/js/highlight/styles/default.min.css"> |
|
| 26 |
+ <link rel="stylesheet" href="/publish/js/highlight/styles/arta.css"> |
|
| 23 | 27 |
<script> |
| 24 |
- $(function(){
|
|
| 25 |
- $(".tabType1 button").click(function(){
|
|
| 26 |
- $(this).removeAttr("style");
|
|
| 27 |
- }) |
|
| 28 |
- }) |
|
| 28 |
+ hljs.highlightAll(); |
|
| 29 | 29 |
</script> |
| 30 |
- |
|
| 30 |
+ <!-- //플러그인 --> |
|
| 31 |
+ |
|
| 31 | 32 |
</head> |
| 32 | 33 |
|
| 33 | 34 |
<body> |
... | ... | @@ -334,17 +335,27 @@ |
| 334 | 335 |
<div class="box"> |
| 335 | 336 |
<div class="title">[Example]</div> |
| 336 | 337 |
<div class="code_view"> |
| 337 |
- <p>{</p> |
|
| 338 |
- <div class="indent"> |
|
| 339 |
- <p><span>"mberId"</span>:"홍길동"</p> |
|
| 340 |
- <p>,<span>"accessKey"</span>:"XXXXXXXXXXXXXX414050694b953"</p> |
|
| 341 |
- <p>,<span>"callFrom"</span>:"01012341234"</p> |
|
| 342 |
- <p>,<span>"callToList"</span>:"01011111111,01022222222,01033333333"</p> |
|
| 343 |
- <p>,<span>"smsTxt"</span>:"문자 테스트~![*이름*]"</p> |
|
| 344 |
- <p>,<span>"nameStr"</span>:"홍길동1|홍길동2|홍길동3"</p> |
|
| 345 |
- <p>,<span>"test_yn"</span>:""</p> |
|
| 346 |
- </div> |
|
| 347 |
- <p class="l_code">}</p> |
|
| 338 |
+ <pre> |
|
| 339 |
+ <code class="language-json"> |
|
| 340 |
+{ |
|
| 341 |
+ |
|
| 342 |
+ "mberId":"홍길동" |
|
| 343 |
+ |
|
| 344 |
+ ,"accessKey":"XXXXXXXXXXXXXX414050694b953" |
|
| 345 |
+ |
|
| 346 |
+ ,"callFrom":"01012341234" |
|
| 347 |
+ |
|
| 348 |
+ ,"callToList":"01011111111,01022222222,01033333333" |
|
| 349 |
+ |
|
| 350 |
+ ,"smsTxt":"문자 테스트~![*이름*]" |
|
| 351 |
+ |
|
| 352 |
+ ,"nameStr":"홍길동1|홍길동2|홍길동3" |
|
| 353 |
+ |
|
| 354 |
+ ,"test_yn":"" |
|
| 355 |
+ |
|
| 356 |
+} |
|
| 357 |
+ </code> |
|
| 358 |
+ </pre> |
|
| 348 | 359 |
</div> |
| 349 | 360 |
</div> |
| 350 | 361 |
<!--// Request--> |
... | ... | @@ -4606,6 +4617,7 @@ |
| 4606 | 4617 |
<!-- footer --> |
| 4607 | 4618 |
<div data-include-path="/publish/layout/_footer.html"></div> |
| 4608 | 4619 |
<!--// footer 영역 --> |
| 4620 |
+ |
|
| 4609 | 4621 |
</body> |
| 4610 | 4622 |
|
| 4611 | 4623 |
</html>(No newline at end of file) |
--- src/main/webapp/publish/css/content.css
+++ src/main/webapp/publish/css/content.css
... | ... | @@ -13,10 +13,10 @@ |
| 13 | 13 |
.c_222 {color: #222 !important;}
|
| 14 | 14 |
.c_666 {color: #666 !important;}
|
| 15 | 15 |
/* 발송결과 화면개선 */ |
| 16 |
-.c_666_g {color: #666 !important; font-size: 26px; font-weight: 600; font-family: 'GmarketSansBold'; padding:0 4px 0 0;}
|
|
| 17 |
-.c_002c9a_g {color: #002c9a !important; font-size: 26px; font-weight: 600; font-family: 'GmarketSansBold'; padding:0 4px 0 0;}
|
|
| 18 |
-.c_e40000_g {color: #e40000 !important; font-size: 26px; font-weight: 600; font-family: 'GmarketSansBold'; padding:0 4px 0 0;}
|
|
| 19 |
-.c_222_g {color: #222 !important; font-size: 26px; font-weight: 600; font-family: 'GmarketSansBold'; padding:0 4px 0 0;}
|
|
| 16 |
+.c_666_g {color: #666 !important; font-size: 26px; font-family: 'GmarketSansBold'; padding:0 4px 0 0;}
|
|
| 17 |
+.c_002c9a_g {color: #002c9a !important; font-size: 26px; font-family: 'GmarketSansBold'; padding:0 4px 0 0;}
|
|
| 18 |
+.c_e40000_g {color: #e40000 !important; font-size: 26px; font-family: 'GmarketSansBold'; padding:0 4px 0 0;}
|
|
| 19 |
+.c_222_g {color: #222 !important; font-size: 26px; font-family: 'GmarketSansBold'; padding:0 4px 0 0;}
|
|
| 20 | 20 |
/*// 발송결과 화면개선 */ |
| 21 | 21 |
.table {display: table;width: 100%;}
|
| 22 | 22 |
.table_cell {display: table-cell;vertical-align: middle;}
|
... | ... | @@ -1121,7 +1121,7 @@ |
| 1121 | 1121 |
/* 사용내역 */ |
| 1122 | 1122 |
.hisroy_price {display: flex; justify-content: space-between; margin-bottom: 30px;}
|
| 1123 | 1123 |
.hisroy_price .hisroy_price_in {background-color: #f2f2f2; width: calc(100%/3 - 20px); padding: 28px 22px; border-radius: 5px; box-sizing: border-box;}
|
| 1124 |
-.hisroy_price .hisroy_price_in>p {font-size: 22px; font-weight: 600; margin-bottom: 25px; font-family: 'GmarketSansBold';}
|
|
| 1124 |
+.hisroy_price .hisroy_price_in>p {font-size: 22px; margin-bottom: 25px; font-family: 'GmarketSansBold';}
|
|
| 1125 | 1125 |
.hisroy_price .hisroy_price_in i{background-size: 100%;}
|
| 1126 | 1126 |
.hisroy_price .hisroy_price_in:nth-child(1) i {background-image: url(/publish/images/content/history_icon1.png); width: 23px; height: 26px; margin: 0 10px 2px 0;}
|
| 1127 | 1127 |
.hisroy_price .hisroy_price_in:nth-child(2) i {background-image: url(/publish/images/content/history_icon2.png); width: 26px; height: 24px; margin: 0 10px 2px 0;}
|
... | ... | @@ -1132,7 +1132,7 @@ |
| 1132 | 1132 |
.hisroy_price .hisroy_price_in>div>p:first-child {float: left;}
|
| 1133 | 1133 |
.hisroy_price .hisroy_price_in>div>p:last-child {float: right;}
|
| 1134 | 1134 |
.hisroy_price .hisroy_price_in>div>p>span {font-size: 22px; font-family: 'GmarketSansBold'; color: #002c9a; padding-right: 5px;}
|
| 1135 |
- |
|
| 1135 |
+#payUserListLoad .pay_cont .tType4 td p .btnType20{margin:0;}
|
|
| 1136 | 1136 |
.price_history_cont .tType4 .btnType20{margin:0;}
|
| 1137 | 1137 |
|
| 1138 | 1138 |
/*후불회원 요금 사용내역*/ |
... | ... | @@ -1453,7 +1453,7 @@ |
| 1453 | 1453 |
.rev_admin_cont {background-color: #fff;padding: 40px;border-radius: 10px; min-height: 589px;}
|
| 1454 | 1454 |
.rev_admin {display: flex; justify-content: space-between; margin-bottom: 20px;}
|
| 1455 | 1455 |
.rev_admin .rev_admin_in {background-color: #f2f2f2; width: calc(100%/4 - 20px); padding: 25px; border-radius: 5px; box-sizing: border-box;}
|
| 1456 |
-.rev_admin .rev_admin_in .rev_admin_top p:first-child {font-size: 22px; font-weight: 600; font-family: 'GmarketSansBold'; float: left;}
|
|
| 1456 |
+.rev_admin .rev_admin_in .rev_admin_top p:first-child {font-size: 22px; font-family: 'GmarketSansBold'; float: left;}
|
|
| 1457 | 1457 |
.rev_admin .rev_admin_in .rev_admin_top p:last-child {font-size: 16px; font-weight: 300; float: right;}
|
| 1458 | 1458 |
.rev_admin .rev_admin_in .rev_admin_top p:last-child span {font-size: 20px; font-weight: 600; font-family: 'GmarketSansBold'; color: #002c9a;}
|
| 1459 | 1459 |
/* .rev_admin .rev_admin_in .rev_admin_btm {background-color: #fff; padding: 12px 0; border-radius: 5px; margin-top: 12px; box-sizing: border-box; display: flex;justify-content:space-between;}
|
... | ... | @@ -2137,7 +2137,7 @@ |
| 2137 | 2137 |
.api_guide_cont ul.info {border:solid 3px #ddd; border-radius: 5px; padding:18px 0 18px 27px; }
|
| 2138 | 2138 |
.api_guide_cont ul.info li { font-size:16px; color:#666; font-weight: 300; line-height: 1.6;}
|
| 2139 | 2139 |
.api_guide_cont .re_cont .req_title {background:url(/publish/images/api_intro_cont/icon_api_request.jpg) 0 5px no-repeat; padding:0 0 0 30px; font-size:26px; font-weight:bold; letter-spacing: -1px; margin:40px 0 0 0;}
|
| 2140 |
- /* api 사용안내, 예제 다운로드 공통 사용*/ |
|
| 2140 |
+ /* api 사용안내, 예제 다운로드 공통 사용*/ |
|
| 2141 | 2141 |
.api_guide_cont .box {background:#f2f2f2; border-radius: 5px; padding:30px; margin: 15px 0 30px 0;}
|
| 2142 | 2142 |
.api_guide_cont .box .text {background:#fff; border-radius: 5px; padding:30px 25px;}
|
| 2143 | 2143 |
.api_guide_cont .box .text h4 {font-size:20px; color:#222; font-weight:bold; letter-spacing: -1px; }
|
... | ... | @@ -2146,8 +2146,13 @@ |
| 2146 | 2146 |
.api_guide_cont .box .text table th {width:210px; text-align: left; text-indent: 18px; line-height: 1.2; background:#f5f5f5; font-size:16px; padding:10px 0;}
|
| 2147 | 2147 |
.api_guide_cont .box .text table td {text-indent: 18px; font-weight: 200;}
|
| 2148 | 2148 |
|
| 2149 |
+.api_guide_cont .code_view pre code.hljs{padding:0;background:transparent;overflow:unset;}
|
|
| 2150 |
+.api_guide_cont .code_view .hljs-attr{color:#fbc72b;}
|
|
| 2151 |
+.api_guide_cont .code_view .hljs-string,.api_guide_cont .code_view .hljs-punctuation,.api_guide_cont .code_view .hljs-tag{color:#fff;}
|
|
| 2152 |
+ |
|
| 2149 | 2153 |
.api_guide_cont .api_guide#tab5_1 .list_tab_wrap2.type3 li{width:calc(100%/5)}
|
| 2150 |
- /* // api 사용안내, 예제 다운로드 공통 사용*/ |
|
| 2154 |
+ |
|
| 2155 |
+ /* // api 사용안내, 예제 다운로드 공통 사용*/ |
|
| 2151 | 2156 |
.api_guide_cont .re_cont .type_table table {width:100%; margin:40px 0 7px 0;}
|
| 2152 | 2157 |
.api_guide_cont .re_cont .type_table table thead th {border-top:1px solid #000; border-left:1px solid #e5e5e5; border-bottom:1px solid #e5e5e5; background:#f7f7f7; padding: 15px 0; }
|
| 2153 | 2158 |
.api_guide_cont .re_cont .type_table table thead th:first-child {border-left:none;}
|
... | ... | @@ -2214,7 +2219,7 @@ |
| 2214 | 2219 |
/* 발송결과 상세 */ |
| 2215 | 2220 |
.res_info {display: flex; justify-content: space-between; margin-bottom: 20px; flex-wrap: wrap; flex-direction:row; }
|
| 2216 | 2221 |
.res_info .res_info_in {background-color: #f2f2f2; width:100%; padding: 34px 44px 44px 44px; border-radius: 5px; box-sizing: border-box;}
|
| 2217 |
-.res_info .res_info_in .res_info_top p:first-child {font-size: 22px; font-weight: 600; font-family: 'GmarketSansBold'; float: left; padding:10px 0 0 0;}
|
|
| 2222 |
+.res_info .res_info_in .res_info_top p:first-child {font-size: 22px; font-family: 'GmarketSansBold'; float: left; padding:10px 0 0 0;}
|
|
| 2218 | 2223 |
.res_info .res_info_in .res_info_top p:last-child {font-size: 16px; font-weight: 300; float: right;}
|
| 2219 | 2224 |
.res_info .res_info_in .res_info_top .btnType.btnType3 {width:76px; font-size:15px;}
|
| 2220 | 2225 |
/*.res_info .res_info_in .res_info_top p:last-child span {font-size: 20px; font-weight: 600; font-family: 'GmarketSansBold'; color: #002c9a;}*/
|
... | ... | @@ -2225,7 +2230,7 @@ |
| 2225 | 2230 |
.res_info .res_info_in .res_info_btm dl dt.btm_charge {font-size:16px;}
|
| 2226 | 2231 |
.res_info .res_info_in .res_info_btm dl dd span {font-weight:500;}
|
| 2227 | 2232 |
|
| 2228 |
-.res_info .res_info_in .res_info_btm dl dd .stcharge {font-size: 20px; font-weight: 600; font-family: 'GmarketSansBold'; color: #222; padding:0 3px 0 0;}
|
|
| 2233 |
+.res_info .res_info_in .res_info_btm dl dd .stcharge {font-size: 20px; font-family: 'GmarketSansBold'; color: #222; padding:0 3px 0 0;}
|
|
| 2229 | 2234 |
|
| 2230 | 2235 |
.res_info .res_info_in .res_num {display:flex; justify-content: space-between; /*flex-direction: row; flex-wrap: wrap; width:100%;*/ margin:10px 0 0 0;}
|
| 2231 | 2236 |
.res_info .res_info_in .res_num .res_info_btm1 {width:calc(100%/2 - 5px); padding:10px;background:#fff;border-radius:5px;box-sizing:border-box;}
|
... | ... | @@ -2609,7 +2614,7 @@ |
| 2609 | 2614 |
.sub .election .receipt_number_table_wrap+.list_bottom .list_bottom_right .btn_yellow.fill{padding:0 3px;}
|
| 2610 | 2615 |
|
| 2611 | 2616 |
/* 후불회원 요금사용내역*/ |
| 2612 |
- .hisroy_price .hisroy_defprice_in>p {font-size: 18px; font-weight: 600; margin-bottom: 25px; font-family: 'GmarketSansBold';}
|
|
| 2617 |
+ .hisroy_price .hisroy_defprice_in>p {font-size: 18px; margin-bottom: 25px; font-family: 'GmarketSansBold';}
|
|
| 2613 | 2618 |
.hisroy_price .hisroy_defprice_in>div>p>span {font-size: 17px; font-family: 'GmarketSansBold'; color: #002c9a; padding-right: 1px;}
|
| 2614 | 2619 |
|
| 2615 | 2620 |
/* 카카오톡 설정*/ |
--- src/main/webapp/publish/css/mem.css
+++ src/main/webapp/publish/css/mem.css
... | ... | @@ -152,6 +152,17 @@ |
| 152 | 152 |
.agree_text .policy_list.sec_list li{padding-left: 20px;}
|
| 153 | 153 |
.agree_text .first_list .sec_list{margin-top: 5px;}
|
| 154 | 154 |
.agree_text .first_list .sec_list li{margin-bottom: 0;}
|
| 155 |
+ |
|
| 156 |
+/* .agree_text .tType2{width: 100%; border-top: 1px solid #000; text-align: center; margin:10px 0 10px 0;}
|
|
| 157 |
+.agree_text .tType2 thead tr{background-color: #f7f7f7; border-bottom: 1px solid #e5e5e5;}
|
|
| 158 |
+.agree_text .tType2 thead tr th{height: 46px; font-size: 16px; font-weight: 500; border-right: 1px solid #e5e5e5; vertical-align: middle;}
|
|
| 159 |
+.agree_text .tType2 thead tr th:last-child{border-right: 0;}
|
|
| 160 |
+.agree_text .tType2 tbody tr{border-bottom: 1px solid #e5e5e5;}
|
|
| 161 |
+.agree_text .tType2 tbody tr th{font-size: 16px; font-weight: 500; border-right: 1px solid #e5e5e5; height: 50px; vertical-align: middle;}
|
|
| 162 |
+.agree_text .tType2 tbody tr td{font-size: 16px; font-weight: 300; border-right: 1px solid #e5e5e5; vertical-align: middle; line-height: 1.4; padding:10px 20px;}
|
|
| 163 |
+.agree_text .tType2 tbody tr td.type_left {text-align: left;}
|
|
| 164 |
+.agree_text .tType2 tbody tr td:last-child{border-right: 0;}
|
|
| 165 |
+.agree_text .tType2 tbody tr td:last-child>span {font-weight: 400;} */
|
|
| 155 | 166 |
/* //약관 */ |
| 156 | 167 |
|
| 157 | 168 |
/* //join2 - 약관동의 */ |
... | ... | @@ -304,7 +315,7 @@ |
| 304 | 315 |
|
| 305 | 316 |
/* 메인화면 */ |
| 306 | 317 |
.my_dashboard {margin-top: 40px;}
|
| 307 |
-.my_dashboard .dashboard_title { font-family: 'GmarketSansBold'; font-size: 22px; font-weight: 600; padding-bottom: 25px;}
|
|
| 318 |
+.my_dashboard .dashboard_title { font-family: 'GmarketSansBold'; font-size: 22px; padding-bottom: 25px;}
|
|
| 308 | 319 |
.my_dashboard .my_dashboard_cont1 button,.my_dashboard .my_dashboard_cont3 button {position: absolute; right: 30px; top: 30px; border-radius: 5px;}
|
| 309 | 320 |
.my_dashboard .my_dashboard_cont3 button.btnType20{position: static; vertical-align: baseline; margin: 0 0 0 8px;}
|
| 310 | 321 |
.my_dashboard>div { display: flex; justify-content: space-between; align-items: center;}
|
+++ src/main/webapp/publish/js/highlight/DIGESTS.md
... | ... | @@ -0,0 +1,57 @@ |
| 1 | +## Subresource Integrity | |
| 2 | + | |
| 3 | +If you are loading Highlight.js via CDN you may wish to use [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) to guarantee that you are using a legimitate build of the library. | |
| 4 | + | |
| 5 | +To do this you simply need to add the `integrity` attribute for each JavaScript file you download via CDN. These digests are used by the browser to confirm the files downloaded have not been modified. | |
| 6 | + | |
| 7 | +```html | |
| 8 | +<script | |
| 9 | + src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/highlight.min.js" | |
| 10 | + integrity="sha384-5xdYoZ0Lt6Jw8GFfRP91J0jaOVUq7DGI1J5wIyNi0D+eHVdfUwHR4gW6kPsw489E"></script> | |
| 11 | +<!-- including any other grammars you might need to load --> | |
| 12 | +<script | |
| 13 | + src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.11.1/languages/go.min.js" | |
| 14 | + integrity="sha384-HdearVH8cyfzwBIQOjL/6dSEmZxQ5rJRezN7spps8E7iu+R6utS8c2ab0AgBNFfH"></script> | |
| 15 | +``` | |
| 16 | + | |
| 17 | +The full list of digests for every file can be found below. | |
| 18 | + | |
| 19 | +### Digests | |
| 20 | + | |
| 21 | +``` | |
| 22 | +sha384-uC39e4pRTIrenlpo9NQf2taOPhdRJNaZLFASSg+Q8BLjYqLXvxL8brjzQmJEQ0qn /es/languages/http.js | |
| 23 | +sha384-36ZwsK42N/jk3DquJeJr/r/oziBOtUxBcg0ZdTaaEDX+Zo/UMgBP4S2Sf4NEyq1y /es/languages/http.min.js | |
| 24 | +sha384-lk+aAr+DNq8Rz3hXPSZ7ga38GS+tQfXDvexuUnyDCSju1t1SAsLipVIFGlRtcUjE /es/languages/java.js | |
| 25 | +sha384-5GpB6kfA2w03pZhAUmmNSYvR5pLvne/Rzqc22BmHv+t9ES7ifMX/ZE7x5TBeqW4d /es/languages/java.min.js | |
| 26 | +sha384-g7t9fKR5Tvod4iWv7BQXN+/JMn5GT9sD6FG3h7Fgl+KCv5k4NnnCzEqUe7BMJ9Mv /es/languages/javascript.js | |
| 27 | +sha384-f7huPivS1dV2T5V+g0aJpgsY7WBHWCsioIq30tpNoXGizD65fWJYGuXXVPNI52VB /es/languages/javascript.min.js | |
| 28 | +sha384-8CRS96Xb/ZkZlQU+5ffA03XTN6/xY40QAnsXKB0Y+ow1vza1LAkRNPSrZqGSNo53 /es/languages/json.js | |
| 29 | +sha384-UHzaYxI/rAo84TEK3WlG15gVfPk49XKax76Ccn9qPWYbUxePCEHxjGkV+xp9HcS/ /es/languages/json.min.js | |
| 30 | +sha384-+KkqXkoHKtuOmUzhZ0BjyV0qjljnS+z6i4fELMEg5brFPtmDIog4zZMhylaBTsVi /es/languages/markdown.js | |
| 31 | +sha384-E7UvgBH6skA1FIOcn3B2c68GtJzrmZlOOC5p/fsxwihTZG/bBedJZu5PC1+kGX7q /es/languages/markdown.min.js | |
| 32 | +sha384-4OPZSHQbxzPqFMOXnndxQ6TZTI/B+J4W9aqTCHxAx/dsPS6GG25kT7wdsf66jJ1M /es/languages/php.js | |
| 33 | +sha384-VxmvZ2mUpp1EzFijS40RFvIc7vbv/d5PhMxVFG/3HMpVKD4sVvhdV9LThrJDiw9e /es/languages/php.min.js | |
| 34 | +sha384-s1ZfN6xtlNKAZux8QYAG7upUsit3RwK5XDoCAN3g6Kj33RrIqbmkuGjdNF9RvzPM /es/languages/sql.js | |
| 35 | +sha384-y25cn06synxhYnlKVprZdpakuFWVrm2jvn8pqiF4L85a05CI/6bNeT2+qXbUYIyW /es/languages/sql.min.js | |
| 36 | +sha384-9ECFzM+oWDye4s/MFx3QUXGo4mW43+SyLpWUDeQtWup6GZJ+KHFxVS89PmZt/fzl /es/languages/xml.js | |
| 37 | +sha384-PQrsaWeWrBiE1CFRw8K335CaJuQRTjDGm73vn8bXvlwaw6RyqWObdvMTBS8B75NN /es/languages/xml.min.js | |
| 38 | +sha384-hV7ok3wrc7DrjvcAtn3jI6KlZtpbm+hC4HXrOyRjrl65HjGtTJ5ixGiMSpJRDiDq /languages/http.js | |
| 39 | +sha384-X50fiL5mByDvJRwn0hkUXIEttF5t8hlEFSPUMq42KoryxgI4niflBsviuhahhWJf /languages/http.min.js | |
| 40 | +sha384-Dprg6CdFFkimxaHg7qM7njVaWLMlOLqughixPERBDbm0cHdX6rKujTnJReof8O6m /languages/java.js | |
| 41 | +sha384-e+59xEZvRMXSRGD31B3HOBGAGqhhs+bbkxCqPuJDkSX5QGneIGTIfwdYJckTN3AO /languages/java.min.js | |
| 42 | +sha384-yxv7Fv9ToggiLsR67t98hV5ZRup6XX6xL1Rkbi/cGV5J8y7fosCi9POqlBkiBWFg /languages/javascript.js | |
| 43 | +sha384-tPOrIubtDHoQU7Rqw0o88ilthGO0/4xEZGB47XrQKWhrc1/SchwsDx+AP74u4nk0 /languages/javascript.min.js | |
| 44 | +sha384-pUlqdjoNePvHvdi7GVKJJnh/P2T3EvXXodl5j0JtTkbNC4DRH7gwGbcHFa84bFOP /languages/json.js | |
| 45 | +sha384-3C+cPClJZgjKFYAb0bh35D7im2jasLzgk9eRix3t1c5pk1+x6b+bHghWcdrKwIo3 /languages/json.min.js | |
| 46 | +sha384-Sk9XW/OOutdl6KS1M9Wson0imuqr0LkpoTRDHi5QFH4MWe0aViI5d86BOVkh8Ds0 /languages/markdown.js | |
| 47 | +sha384-Rv26WbhHH4MDPzeExq4ECmZUYF942tlfVhqA91Drw1P+Ey55KjihLF9RJENxjWr1 /languages/markdown.min.js | |
| 48 | +sha384-0XBmTxpMLuDjB2zdfbi3Lv4Yokm2e1YFGZ9mCmI5887Kpi23jMF5N7rPrf0GdoU/ /languages/php.js | |
| 49 | +sha384-Bv/Sxv6HlOzYOdV1iQpJTG3xiqGWIIMq9xsFfEX8ss7oNWMgKqOa/J2WSFG2m7Jd /languages/php.min.js | |
| 50 | +sha384-2sXmcW3eKeNDWiLtuq9NgFJC4NsLBN/fDTzZevmcgBrSERv6iO/k+c7r9T09Fb8J /languages/sql.js | |
| 51 | +sha384-jrnLoVn13sB+/dTfoAYVPhg0tYGQzzuzSGP3WTk8OvKAY0hDejpUXFYYI3bohAyW /languages/sql.min.js | |
| 52 | +sha384-Pgzg6a405W6U1xFjjSs5i8d7V81Tmt/TYn8HFOa+u1psDc8cbs8nC7BuyNXbWWRK /languages/xml.js | |
| 53 | +sha384-FQjSArDMJE4WMAJGcCNAV+IXIOljcIxM3UFAD2vxjedWmBnnDaAyqRG7AQHf/uM/ /languages/xml.min.js | |
| 54 | +sha384-KsOYnI+uTIqConKW46858yINdMX+imylgc43XIMUFLqemTAx3VjoUQW2crTmrQbf /highlight.js | |
| 55 | +sha384-Navugrg24fY7MciWyBN2P9wwUeVu5PV7TuEMSsLt2tWke+cxQMq4bnZWKwsJflWw /highlight.min.js | |
| 56 | +``` | |
| 57 | + |
+++ src/main/webapp/publish/js/highlight/LICENSE
... | ... | @@ -0,0 +1,29 @@ |
| 1 | +BSD 3-Clause License | |
| 2 | + | |
| 3 | +Copyright (c) 2006, Ivan Sagalaev. | |
| 4 | +All rights reserved. | |
| 5 | + | |
| 6 | +Redistribution and use in source and binary forms, with or without | |
| 7 | +modification, are permitted provided that the following conditions are met: | |
| 8 | + | |
| 9 | +* Redistributions of source code must retain the above copyright notice, this | |
| 10 | + list of conditions and the following disclaimer. | |
| 11 | + | |
| 12 | +* Redistributions in binary form must reproduce the above copyright notice, | |
| 13 | + this list of conditions and the following disclaimer in the documentation | |
| 14 | + and/or other materials provided with the distribution. | |
| 15 | + | |
| 16 | +* Neither the name of the copyright holder nor the names of its | |
| 17 | + contributors may be used to endorse or promote products derived from | |
| 18 | + this software without specific prior written permission. | |
| 19 | + | |
| 20 | +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
| 21 | +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
| 22 | +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
| 23 | +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE | |
| 24 | +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
| 25 | +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 26 | +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
| 27 | +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | |
| 28 | +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE | |
| 29 | +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
+++ src/main/webapp/publish/js/highlight/README.md
... | ... | @@ -0,0 +1,45 @@ |
| 1 | +# Highlight.js CDN Assets | |
| 2 | + | |
| 3 | +[](https://packagephobia.now.sh/result?p=highlight.js) | |
| 4 | + | |
| 5 | +**This package contains only the CDN build assets of highlight.js.** | |
| 6 | + | |
| 7 | +This may be what you want if you'd like to install the pre-built distributable highlight.js client-side assets via NPM. If you're wanting to use highlight.js mainly on the server-side you likely want the [highlight.js][1] package instead. | |
| 8 | + | |
| 9 | +To access these files via CDN:<br> | |
| 10 | +https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@latest/build/ | |
| 11 | + | |
| 12 | +**If you just want a single .js file with the common languages built-in: | |
| 13 | +<https://cdn.jsdelivr.net/gh/highlightjs/cdn-release@latest/build/highlight.min.js>** | |
| 14 | + | |
| 15 | +--- | |
| 16 | + | |
| 17 | +## Highlight.js | |
| 18 | + | |
| 19 | +Highlight.js is a syntax highlighter written in JavaScript. It works in | |
| 20 | +the browser as well as on the server. It works with pretty much any | |
| 21 | +markup, doesn’t depend on any framework, and has automatic language | |
| 22 | +detection. | |
| 23 | + | |
| 24 | +If you'd like to read the full README:<br> | |
| 25 | +<https://github.com/highlightjs/highlight.js/blob/main/README.md> | |
| 26 | + | |
| 27 | +## License | |
| 28 | + | |
| 29 | +Highlight.js is released under the BSD License. See [LICENSE][7] file | |
| 30 | +for details. | |
| 31 | + | |
| 32 | +## Links | |
| 33 | + | |
| 34 | +The official site for the library is at <https://highlightjs.org/>. | |
| 35 | + | |
| 36 | +The Github project may be found at: <https://github.com/highlightjs/highlight.js> | |
| 37 | + | |
| 38 | +Further in-depth documentation for the API and other topics is at | |
| 39 | +<http://highlightjs.readthedocs.io/>. | |
| 40 | + | |
| 41 | +A list of the Core Team and contributors can be found in the [CONTRIBUTORS.md][8] file. | |
| 42 | + | |
| 43 | +[1]: https://www.npmjs.com/package/highlight.js | |
| 44 | +[7]: https://github.com/highlightjs/highlight.js/blob/main/LICENSE | |
| 45 | +[8]: https://github.com/highlightjs/highlight.js/blob/main/CONTRIBUTORS.md |
+++ src/main/webapp/publish/js/highlight/es/core.js
... | ... | @@ -0,0 +1,2600 @@ |
| 1 | +/*! | |
| 2 | + Highlight.js v11.11.1 (git: 08cb242e7d) | |
| 3 | + (c) 2006-2025 Josh Goebel <hello@joshgoebel.com> and other contributors | |
| 4 | + License: BSD-3-Clause | |
| 5 | + */ | |
| 6 | +/* eslint-disable no-multi-assign */ | |
| 7 | + | |
| 8 | +function deepFreeze(obj) { | |
| 9 | + if (obj instanceof Map) { | |
| 10 | + obj.clear = | |
| 11 | + obj.delete = | |
| 12 | + obj.set = | |
| 13 | + function () { | |
| 14 | + throw new Error('map is read-only'); | |
| 15 | + }; | |
| 16 | + } else if (obj instanceof Set) { | |
| 17 | + obj.add = | |
| 18 | + obj.clear = | |
| 19 | + obj.delete = | |
| 20 | + function () { | |
| 21 | + throw new Error('set is read-only'); | |
| 22 | + }; | |
| 23 | + } | |
| 24 | + | |
| 25 | + // Freeze self | |
| 26 | + Object.freeze(obj); | |
| 27 | + | |
| 28 | + Object.getOwnPropertyNames(obj).forEach((name) => { | |
| 29 | + const prop = obj[name]; | |
| 30 | + const type = typeof prop; | |
| 31 | + | |
| 32 | + // Freeze prop if it is an object or function and also not already frozen | |
| 33 | + if ((type === 'object' || type === 'function') && !Object.isFrozen(prop)) { | |
| 34 | + deepFreeze(prop); | |
| 35 | + } | |
| 36 | + }); | |
| 37 | + | |
| 38 | + return obj; | |
| 39 | +} | |
| 40 | + | |
| 41 | +/** @typedef {import('highlight.js').CallbackResponse} CallbackResponse */ | |
| 42 | +/** @typedef {import('highlight.js').CompiledMode} CompiledMode */ | |
| 43 | +/** @implements CallbackResponse */ | |
| 44 | + | |
| 45 | +class Response { | |
| 46 | + /** | |
| 47 | + * @param {CompiledMode} mode | |
| 48 | + */ | |
| 49 | + constructor(mode) { | |
| 50 | + // eslint-disable-next-line no-undefined | |
| 51 | + if (mode.data === undefined) mode.data = {}; | |
| 52 | + | |
| 53 | + this.data = mode.data; | |
| 54 | + this.isMatchIgnored = false; | |
| 55 | + } | |
| 56 | + | |
| 57 | + ignoreMatch() { | |
| 58 | + this.isMatchIgnored = true; | |
| 59 | + } | |
| 60 | +} | |
| 61 | + | |
| 62 | +/** | |
| 63 | + * @param {string} value | |
| 64 | + * @returns {string} | |
| 65 | + */ | |
| 66 | +function escapeHTML(value) { | |
| 67 | + return value | |
| 68 | + .replace(/&/g, '&') | |
| 69 | + .replace(/</g, '<') | |
| 70 | + .replace(/>/g, '>') | |
| 71 | + .replace(/"/g, '"') | |
| 72 | + .replace(/'/g, '''); | |
| 73 | +} | |
| 74 | + | |
| 75 | +/** | |
| 76 | + * performs a shallow merge of multiple objects into one | |
| 77 | + * | |
| 78 | + * @template T | |
| 79 | + * @param {T} original | |
| 80 | + * @param {Record<string,any>[]} objects | |
| 81 | + * @returns {T} a single new object | |
| 82 | + */ | |
| 83 | +function inherit$1(original, ...objects) { | |
| 84 | + /** @type Record<string,any> */ | |
| 85 | + const result = Object.create(null); | |
| 86 | + | |
| 87 | + for (const key in original) { | |
| 88 | + result[key] = original[key]; | |
| 89 | + } | |
| 90 | + objects.forEach(function(obj) { | |
| 91 | + for (const key in obj) { | |
| 92 | + result[key] = obj[key]; | |
| 93 | + } | |
| 94 | + }); | |
| 95 | + return /** @type {T} */ (result); | |
| 96 | +} | |
| 97 | + | |
| 98 | +/** | |
| 99 | + * @typedef {object} Renderer | |
| 100 | + * @property {(text: string) => void} addText | |
| 101 | + * @property {(node: Node) => void} openNode | |
| 102 | + * @property {(node: Node) => void} closeNode | |
| 103 | + * @property {() => string} value | |
| 104 | + */ | |
| 105 | + | |
| 106 | +/** @typedef {{scope?: string, language?: string, sublanguage?: boolean}} Node */ | |
| 107 | +/** @typedef {{walk: (r: Renderer) => void}} Tree */ | |
| 108 | +/** */ | |
| 109 | + | |
| 110 | +const SPAN_CLOSE = '</span>'; | |
| 111 | + | |
| 112 | +/** | |
| 113 | + * Determines if a node needs to be wrapped in <span> | |
| 114 | + * | |
| 115 | + * @param {Node} node */ | |
| 116 | +const emitsWrappingTags = (node) => { | |
| 117 | + // rarely we can have a sublanguage where language is undefined | |
| 118 | + // TODO: track down why | |
| 119 | + return !!node.scope; | |
| 120 | +}; | |
| 121 | + | |
| 122 | +/** | |
| 123 | + * | |
| 124 | + * @param {string} name | |
| 125 | + * @param {{prefix:string}} options | |
| 126 | + */ | |
| 127 | +const scopeToCSSClass = (name, { prefix }) => { | |
| 128 | + // sub-language | |
| 129 | + if (name.startsWith("language:")) { | |
| 130 | + return name.replace("language:", "language-"); | |
| 131 | + } | |
| 132 | + // tiered scope: comment.line | |
| 133 | + if (name.includes(".")) { | |
| 134 | + const pieces = name.split("."); | |
| 135 | + return [ | |
| 136 | + `${prefix}${pieces.shift()}`, | |
| 137 | + ...(pieces.map((x, i) => `${x}${"_".repeat(i + 1)}`)) | |
| 138 | + ].join(" "); | |
| 139 | + } | |
| 140 | + // simple scope | |
| 141 | + return `${prefix}${name}`; | |
| 142 | +}; | |
| 143 | + | |
| 144 | +/** @type {Renderer} */ | |
| 145 | +class HTMLRenderer { | |
| 146 | + /** | |
| 147 | + * Creates a new HTMLRenderer | |
| 148 | + * | |
| 149 | + * @param {Tree} parseTree - the parse tree (must support `walk` API) | |
| 150 | + * @param {{classPrefix: string}} options | |
| 151 | + */ | |
| 152 | + constructor(parseTree, options) { | |
| 153 | + this.buffer = ""; | |
| 154 | + this.classPrefix = options.classPrefix; | |
| 155 | + parseTree.walk(this); | |
| 156 | + } | |
| 157 | + | |
| 158 | + /** | |
| 159 | + * Adds texts to the output stream | |
| 160 | + * | |
| 161 | + * @param {string} text */ | |
| 162 | + addText(text) { | |
| 163 | + this.buffer += escapeHTML(text); | |
| 164 | + } | |
| 165 | + | |
| 166 | + /** | |
| 167 | + * Adds a node open to the output stream (if needed) | |
| 168 | + * | |
| 169 | + * @param {Node} node */ | |
| 170 | + openNode(node) { | |
| 171 | + if (!emitsWrappingTags(node)) return; | |
| 172 | + | |
| 173 | + const className = scopeToCSSClass(node.scope, | |
| 174 | + { prefix: this.classPrefix }); | |
| 175 | + this.span(className); | |
| 176 | + } | |
| 177 | + | |
| 178 | + /** | |
| 179 | + * Adds a node close to the output stream (if needed) | |
| 180 | + * | |
| 181 | + * @param {Node} node */ | |
| 182 | + closeNode(node) { | |
| 183 | + if (!emitsWrappingTags(node)) return; | |
| 184 | + | |
| 185 | + this.buffer += SPAN_CLOSE; | |
| 186 | + } | |
| 187 | + | |
| 188 | + /** | |
| 189 | + * returns the accumulated buffer | |
| 190 | + */ | |
| 191 | + value() { | |
| 192 | + return this.buffer; | |
| 193 | + } | |
| 194 | + | |
| 195 | + // helpers | |
| 196 | + | |
| 197 | + /** | |
| 198 | + * Builds a span element | |
| 199 | + * | |
| 200 | + * @param {string} className */ | |
| 201 | + span(className) { | |
| 202 | + this.buffer += `<span class="${className}">`; | |
| 203 | + } | |
| 204 | +} | |
| 205 | + | |
| 206 | +/** @typedef {{scope?: string, language?: string, children: Node[]} | string} Node */ | |
| 207 | +/** @typedef {{scope?: string, language?: string, children: Node[]} } DataNode */ | |
| 208 | +/** @typedef {import('highlight.js').Emitter} Emitter */ | |
| 209 | +/** */ | |
| 210 | + | |
| 211 | +/** @returns {DataNode} */ | |
| 212 | +const newNode = (opts = {}) => { | |
| 213 | + /** @type DataNode */ | |
| 214 | + const result = { children: [] }; | |
| 215 | + Object.assign(result, opts); | |
| 216 | + return result; | |
| 217 | +}; | |
| 218 | + | |
| 219 | +class TokenTree { | |
| 220 | + constructor() { | |
| 221 | + /** @type DataNode */ | |
| 222 | + this.rootNode = newNode(); | |
| 223 | + this.stack = [this.rootNode]; | |
| 224 | + } | |
| 225 | + | |
| 226 | + get top() { | |
| 227 | + return this.stack[this.stack.length - 1]; | |
| 228 | + } | |
| 229 | + | |
| 230 | + get root() { return this.rootNode; } | |
| 231 | + | |
| 232 | + /** @param {Node} node */ | |
| 233 | + add(node) { | |
| 234 | + this.top.children.push(node); | |
| 235 | + } | |
| 236 | + | |
| 237 | + /** @param {string} scope */ | |
| 238 | + openNode(scope) { | |
| 239 | + /** @type Node */ | |
| 240 | + const node = newNode({ scope }); | |
| 241 | + this.add(node); | |
| 242 | + this.stack.push(node); | |
| 243 | + } | |
| 244 | + | |
| 245 | + closeNode() { | |
| 246 | + if (this.stack.length > 1) { | |
| 247 | + return this.stack.pop(); | |
| 248 | + } | |
| 249 | + // eslint-disable-next-line no-undefined | |
| 250 | + return undefined; | |
| 251 | + } | |
| 252 | + | |
| 253 | + closeAllNodes() { | |
| 254 | + while (this.closeNode()); | |
| 255 | + } | |
| 256 | + | |
| 257 | + toJSON() { | |
| 258 | + return JSON.stringify(this.rootNode, null, 4); | |
| 259 | + } | |
| 260 | + | |
| 261 | + /** | |
| 262 | + * @typedef { import("./html_renderer").Renderer } Renderer | |
| 263 | + * @param {Renderer} builder | |
| 264 | + */ | |
| 265 | + walk(builder) { | |
| 266 | + // this does not | |
| 267 | + return this.constructor._walk(builder, this.rootNode); | |
| 268 | + // this works | |
| 269 | + // return TokenTree._walk(builder, this.rootNode); | |
| 270 | + } | |
| 271 | + | |
| 272 | + /** | |
| 273 | + * @param {Renderer} builder | |
| 274 | + * @param {Node} node | |
| 275 | + */ | |
| 276 | + static _walk(builder, node) { | |
| 277 | + if (typeof node === "string") { | |
| 278 | + builder.addText(node); | |
| 279 | + } else if (node.children) { | |
| 280 | + builder.openNode(node); | |
| 281 | + node.children.forEach((child) => this._walk(builder, child)); | |
| 282 | + builder.closeNode(node); | |
| 283 | + } | |
| 284 | + return builder; | |
| 285 | + } | |
| 286 | + | |
| 287 | + /** | |
| 288 | + * @param {Node} node | |
| 289 | + */ | |
| 290 | + static _collapse(node) { | |
| 291 | + if (typeof node === "string") return; | |
| 292 | + if (!node.children) return; | |
| 293 | + | |
| 294 | + if (node.children.every(el => typeof el === "string")) { | |
| 295 | + // node.text = node.children.join(""); | |
| 296 | + // delete node.children; | |
| 297 | + node.children = [node.children.join("")]; | |
| 298 | + } else { | |
| 299 | + node.children.forEach((child) => { | |
| 300 | + TokenTree._collapse(child); | |
| 301 | + }); | |
| 302 | + } | |
| 303 | + } | |
| 304 | +} | |
| 305 | + | |
| 306 | +/** | |
| 307 | + Currently this is all private API, but this is the minimal API necessary | |
| 308 | + that an Emitter must implement to fully support the parser. | |
| 309 | + | |
| 310 | + Minimal interface: | |
| 311 | + | |
| 312 | + - addText(text) | |
| 313 | + - __addSublanguage(emitter, subLanguageName) | |
| 314 | + - startScope(scope) | |
| 315 | + - endScope() | |
| 316 | + - finalize() | |
| 317 | + - toHTML() | |
| 318 | + | |
| 319 | +*/ | |
| 320 | + | |
| 321 | +/** | |
| 322 | + * @implements {Emitter} | |
| 323 | + */ | |
| 324 | +class TokenTreeEmitter extends TokenTree { | |
| 325 | + /** | |
| 326 | + * @param {*} options | |
| 327 | + */ | |
| 328 | + constructor(options) { | |
| 329 | + super(); | |
| 330 | + this.options = options; | |
| 331 | + } | |
| 332 | + | |
| 333 | + /** | |
| 334 | + * @param {string} text | |
| 335 | + */ | |
| 336 | + addText(text) { | |
| 337 | + if (text === "") { return; } | |
| 338 | + | |
| 339 | + this.add(text); | |
| 340 | + } | |
| 341 | + | |
| 342 | + /** @param {string} scope */ | |
| 343 | + startScope(scope) { | |
| 344 | + this.openNode(scope); | |
| 345 | + } | |
| 346 | + | |
| 347 | + endScope() { | |
| 348 | + this.closeNode(); | |
| 349 | + } | |
| 350 | + | |
| 351 | + /** | |
| 352 | + * @param {Emitter & {root: DataNode}} emitter | |
| 353 | + * @param {string} name | |
| 354 | + */ | |
| 355 | + __addSublanguage(emitter, name) { | |
| 356 | + /** @type DataNode */ | |
| 357 | + const node = emitter.root; | |
| 358 | + if (name) node.scope = `language:${name}`; | |
| 359 | + | |
| 360 | + this.add(node); | |
| 361 | + } | |
| 362 | + | |
| 363 | + toHTML() { | |
| 364 | + const renderer = new HTMLRenderer(this, this.options); | |
| 365 | + return renderer.value(); | |
| 366 | + } | |
| 367 | + | |
| 368 | + finalize() { | |
| 369 | + this.closeAllNodes(); | |
| 370 | + return true; | |
| 371 | + } | |
| 372 | +} | |
| 373 | + | |
| 374 | +/** | |
| 375 | + * @param {string} value | |
| 376 | + * @returns {RegExp} | |
| 377 | + * */ | |
| 378 | + | |
| 379 | +/** | |
| 380 | + * @param {RegExp | string } re | |
| 381 | + * @returns {string} | |
| 382 | + */ | |
| 383 | +function source(re) { | |
| 384 | + if (!re) return null; | |
| 385 | + if (typeof re === "string") return re; | |
| 386 | + | |
| 387 | + return re.source; | |
| 388 | +} | |
| 389 | + | |
| 390 | +/** | |
| 391 | + * @param {RegExp | string } re | |
| 392 | + * @returns {string} | |
| 393 | + */ | |
| 394 | +function lookahead(re) { | |
| 395 | + return concat('(?=', re, ')'); | |
| 396 | +} | |
| 397 | + | |
| 398 | +/** | |
| 399 | + * @param {RegExp | string } re | |
| 400 | + * @returns {string} | |
| 401 | + */ | |
| 402 | +function anyNumberOfTimes(re) { | |
| 403 | + return concat('(?:', re, ')*'); | |
| 404 | +} | |
| 405 | + | |
| 406 | +/** | |
| 407 | + * @param {RegExp | string } re | |
| 408 | + * @returns {string} | |
| 409 | + */ | |
| 410 | +function optional(re) { | |
| 411 | + return concat('(?:', re, ')?'); | |
| 412 | +} | |
| 413 | + | |
| 414 | +/** | |
| 415 | + * @param {...(RegExp | string) } args | |
| 416 | + * @returns {string} | |
| 417 | + */ | |
| 418 | +function concat(...args) { | |
| 419 | + const joined = args.map((x) => source(x)).join(""); | |
| 420 | + return joined; | |
| 421 | +} | |
| 422 | + | |
| 423 | +/** | |
| 424 | + * @param { Array<string | RegExp | Object> } args | |
| 425 | + * @returns {object} | |
| 426 | + */ | |
| 427 | +function stripOptionsFromArgs(args) { | |
| 428 | + const opts = args[args.length - 1]; | |
| 429 | + | |
| 430 | + if (typeof opts === 'object' && opts.constructor === Object) { | |
| 431 | + args.splice(args.length - 1, 1); | |
| 432 | + return opts; | |
| 433 | + } else { | |
| 434 | + return {}; | |
| 435 | + } | |
| 436 | +} | |
| 437 | + | |
| 438 | +/** @typedef { {capture?: boolean} } RegexEitherOptions */ | |
| 439 | + | |
| 440 | +/** | |
| 441 | + * Any of the passed expresssions may match | |
| 442 | + * | |
| 443 | + * Creates a huge this | this | that | that match | |
| 444 | + * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args | |
| 445 | + * @returns {string} | |
| 446 | + */ | |
| 447 | +function either(...args) { | |
| 448 | + /** @type { object & {capture?: boolean} } */ | |
| 449 | + const opts = stripOptionsFromArgs(args); | |
| 450 | + const joined = '(' | |
| 451 | + + (opts.capture ? "" : "?:") | |
| 452 | + + args.map((x) => source(x)).join("|") + ")"; | |
| 453 | + return joined; | |
| 454 | +} | |
| 455 | + | |
| 456 | +/** | |
| 457 | + * @param {RegExp | string} re | |
| 458 | + * @returns {number} | |
| 459 | + */ | |
| 460 | +function countMatchGroups(re) { | |
| 461 | + return (new RegExp(re.toString() + '|')).exec('').length - 1; | |
| 462 | +} | |
| 463 | + | |
| 464 | +/** | |
| 465 | + * Does lexeme start with a regular expression match at the beginning | |
| 466 | + * @param {RegExp} re | |
| 467 | + * @param {string} lexeme | |
| 468 | + */ | |
| 469 | +function startsWith(re, lexeme) { | |
| 470 | + const match = re && re.exec(lexeme); | |
| 471 | + return match && match.index === 0; | |
| 472 | +} | |
| 473 | + | |
| 474 | +// BACKREF_RE matches an open parenthesis or backreference. To avoid | |
| 475 | +// an incorrect parse, it additionally matches the following: | |
| 476 | +// - [...] elements, where the meaning of parentheses and escapes change | |
| 477 | +// - other escape sequences, so we do not misparse escape sequences as | |
| 478 | +// interesting elements | |
| 479 | +// - non-matching or lookahead parentheses, which do not capture. These | |
| 480 | +// follow the '(' with a '?'. | |
| 481 | +const BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./; | |
| 482 | + | |
| 483 | +// **INTERNAL** Not intended for outside usage | |
| 484 | +// join logically computes regexps.join(separator), but fixes the | |
| 485 | +// backreferences so they continue to match. | |
| 486 | +// it also places each individual regular expression into it's own | |
| 487 | +// match group, keeping track of the sequencing of those match groups | |
| 488 | +// is currently an exercise for the caller. :-) | |
| 489 | +/** | |
| 490 | + * @param {(string | RegExp)[]} regexps | |
| 491 | + * @param {{joinWith: string}} opts | |
| 492 | + * @returns {string} | |
| 493 | + */ | |
| 494 | +function _rewriteBackreferences(regexps, { joinWith }) { | |
| 495 | + let numCaptures = 0; | |
| 496 | + | |
| 497 | + return regexps.map((regex) => { | |
| 498 | + numCaptures += 1; | |
| 499 | + const offset = numCaptures; | |
| 500 | + let re = source(regex); | |
| 501 | + let out = ''; | |
| 502 | + | |
| 503 | + while (re.length > 0) { | |
| 504 | + const match = BACKREF_RE.exec(re); | |
| 505 | + if (!match) { | |
| 506 | + out += re; | |
| 507 | + break; | |
| 508 | + } | |
| 509 | + out += re.substring(0, match.index); | |
| 510 | + re = re.substring(match.index + match[0].length); | |
| 511 | + if (match[0][0] === '\\' && match[1]) { | |
| 512 | + // Adjust the backreference. | |
| 513 | + out += '\\' + String(Number(match[1]) + offset); | |
| 514 | + } else { | |
| 515 | + out += match[0]; | |
| 516 | + if (match[0] === '(') { | |
| 517 | + numCaptures++; | |
| 518 | + } | |
| 519 | + } | |
| 520 | + } | |
| 521 | + return out; | |
| 522 | + }).map(re => `(${re})`).join(joinWith); | |
| 523 | +} | |
| 524 | + | |
| 525 | +/** @typedef {import('highlight.js').Mode} Mode */ | |
| 526 | +/** @typedef {import('highlight.js').ModeCallback} ModeCallback */ | |
| 527 | + | |
| 528 | +// Common regexps | |
| 529 | +const MATCH_NOTHING_RE = /\b\B/; | |
| 530 | +const IDENT_RE = '[a-zA-Z]\\w*'; | |
| 531 | +const UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*'; | |
| 532 | +const NUMBER_RE = '\\b\\d+(\\.\\d+)?'; | |
| 533 | +const C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float | |
| 534 | +const BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b... | |
| 535 | +const RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; | |
| 536 | + | |
| 537 | +/** | |
| 538 | +* @param { Partial<Mode> & {binary?: string | RegExp} } opts | |
| 539 | +*/ | |
| 540 | +const SHEBANG = (opts = {}) => { | |
| 541 | + const beginShebang = /^#![ ]*\//; | |
| 542 | + if (opts.binary) { | |
| 543 | + opts.begin = concat( | |
| 544 | + beginShebang, | |
| 545 | + /.*\b/, | |
| 546 | + opts.binary, | |
| 547 | + /\b.*/); | |
| 548 | + } | |
| 549 | + return inherit$1({ | |
| 550 | + scope: 'meta', | |
| 551 | + begin: beginShebang, | |
| 552 | + end: /$/, | |
| 553 | + relevance: 0, | |
| 554 | + /** @type {ModeCallback} */ | |
| 555 | + "on:begin": (m, resp) => { | |
| 556 | + if (m.index !== 0) resp.ignoreMatch(); | |
| 557 | + } | |
| 558 | + }, opts); | |
| 559 | +}; | |
| 560 | + | |
| 561 | +// Common modes | |
| 562 | +const BACKSLASH_ESCAPE = { | |
| 563 | + begin: '\\\\[\\s\\S]', relevance: 0 | |
| 564 | +}; | |
| 565 | +const APOS_STRING_MODE = { | |
| 566 | + scope: 'string', | |
| 567 | + begin: '\'', | |
| 568 | + end: '\'', | |
| 569 | + illegal: '\\n', | |
| 570 | + contains: [BACKSLASH_ESCAPE] | |
| 571 | +}; | |
| 572 | +const QUOTE_STRING_MODE = { | |
| 573 | + scope: 'string', | |
| 574 | + begin: '"', | |
| 575 | + end: '"', | |
| 576 | + illegal: '\\n', | |
| 577 | + contains: [BACKSLASH_ESCAPE] | |
| 578 | +}; | |
| 579 | +const PHRASAL_WORDS_MODE = { | |
| 580 | + begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ | |
| 581 | +}; | |
| 582 | +/** | |
| 583 | + * Creates a comment mode | |
| 584 | + * | |
| 585 | + * @param {string | RegExp} begin | |
| 586 | + * @param {string | RegExp} end | |
| 587 | + * @param {Mode | {}} [modeOptions] | |
| 588 | + * @returns {Partial<Mode>} | |
| 589 | + */ | |
| 590 | +const COMMENT = function(begin, end, modeOptions = {}) { | |
| 591 | + const mode = inherit$1( | |
| 592 | + { | |
| 593 | + scope: 'comment', | |
| 594 | + begin, | |
| 595 | + end, | |
| 596 | + contains: [] | |
| 597 | + }, | |
| 598 | + modeOptions | |
| 599 | + ); | |
| 600 | + mode.contains.push({ | |
| 601 | + scope: 'doctag', | |
| 602 | + // hack to avoid the space from being included. the space is necessary to | |
| 603 | + // match here to prevent the plain text rule below from gobbling up doctags | |
| 604 | + begin: '[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)', | |
| 605 | + end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/, | |
| 606 | + excludeBegin: true, | |
| 607 | + relevance: 0 | |
| 608 | + }); | |
| 609 | + const ENGLISH_WORD = either( | |
| 610 | + // list of common 1 and 2 letter words in English | |
| 611 | + "I", | |
| 612 | + "a", | |
| 613 | + "is", | |
| 614 | + "so", | |
| 615 | + "us", | |
| 616 | + "to", | |
| 617 | + "at", | |
| 618 | + "if", | |
| 619 | + "in", | |
| 620 | + "it", | |
| 621 | + "on", | |
| 622 | + // note: this is not an exhaustive list of contractions, just popular ones | |
| 623 | + /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, // contractions - can't we'd they're let's, etc | |
| 624 | + /[A-Za-z]+[-][a-z]+/, // `no-way`, etc. | |
| 625 | + /[A-Za-z][a-z]{2,}/ // allow capitalized words at beginning of sentences | |
| 626 | + ); | |
| 627 | + // looking like plain text, more likely to be a comment | |
| 628 | + mode.contains.push( | |
| 629 | + { | |
| 630 | + // TODO: how to include ", (, ) without breaking grammars that use these for | |
| 631 | + // comment delimiters? | |
| 632 | + // begin: /[ ]+([()"]?([A-Za-z'-]{3,}|is|a|I|so|us|[tT][oO]|at|if|in|it|on)[.]?[()":]?([.][ ]|[ ]|\))){3}/ | |
| 633 | + // --- | |
| 634 | + | |
| 635 | + // this tries to find sequences of 3 english words in a row (without any | |
| 636 | + // "programming" type syntax) this gives us a strong signal that we've | |
| 637 | + // TRULY found a comment - vs perhaps scanning with the wrong language. | |
| 638 | + // It's possible to find something that LOOKS like the start of the | |
| 639 | + // comment - but then if there is no readable text - good chance it is a | |
| 640 | + // false match and not a comment. | |
| 641 | + // | |
| 642 | + // for a visual example please see: | |
| 643 | + // https://github.com/highlightjs/highlight.js/issues/2827 | |
| 644 | + | |
| 645 | + begin: concat( | |
| 646 | + /[ ]+/, // necessary to prevent us gobbling up doctags like /* @author Bob Mcgill */ | |
| 647 | + '(', | |
| 648 | + ENGLISH_WORD, | |
| 649 | + /[.]?[:]?([.][ ]|[ ])/, | |
| 650 | + '){3}') // look for 3 words in a row | |
| 651 | + } | |
| 652 | + ); | |
| 653 | + return mode; | |
| 654 | +}; | |
| 655 | +const C_LINE_COMMENT_MODE = COMMENT('//', '$'); | |
| 656 | +const C_BLOCK_COMMENT_MODE = COMMENT('/\\*', '\\*/'); | |
| 657 | +const HASH_COMMENT_MODE = COMMENT('#', '$'); | |
| 658 | +const NUMBER_MODE = { | |
| 659 | + scope: 'number', | |
| 660 | + begin: NUMBER_RE, | |
| 661 | + relevance: 0 | |
| 662 | +}; | |
| 663 | +const C_NUMBER_MODE = { | |
| 664 | + scope: 'number', | |
| 665 | + begin: C_NUMBER_RE, | |
| 666 | + relevance: 0 | |
| 667 | +}; | |
| 668 | +const BINARY_NUMBER_MODE = { | |
| 669 | + scope: 'number', | |
| 670 | + begin: BINARY_NUMBER_RE, | |
| 671 | + relevance: 0 | |
| 672 | +}; | |
| 673 | +const REGEXP_MODE = { | |
| 674 | + scope: "regexp", | |
| 675 | + begin: /\/(?=[^/\n]*\/)/, | |
| 676 | + end: /\/[gimuy]*/, | |
| 677 | + contains: [ | |
| 678 | + BACKSLASH_ESCAPE, | |
| 679 | + { | |
| 680 | + begin: /\[/, | |
| 681 | + end: /\]/, | |
| 682 | + relevance: 0, | |
| 683 | + contains: [BACKSLASH_ESCAPE] | |
| 684 | + } | |
| 685 | + ] | |
| 686 | +}; | |
| 687 | +const TITLE_MODE = { | |
| 688 | + scope: 'title', | |
| 689 | + begin: IDENT_RE, | |
| 690 | + relevance: 0 | |
| 691 | +}; | |
| 692 | +const UNDERSCORE_TITLE_MODE = { | |
| 693 | + scope: 'title', | |
| 694 | + begin: UNDERSCORE_IDENT_RE, | |
| 695 | + relevance: 0 | |
| 696 | +}; | |
| 697 | +const METHOD_GUARD = { | |
| 698 | + // excludes method names from keyword processing | |
| 699 | + begin: '\\.\\s*' + UNDERSCORE_IDENT_RE, | |
| 700 | + relevance: 0 | |
| 701 | +}; | |
| 702 | + | |
| 703 | +/** | |
| 704 | + * Adds end same as begin mechanics to a mode | |
| 705 | + * | |
| 706 | + * Your mode must include at least a single () match group as that first match | |
| 707 | + * group is what is used for comparison | |
| 708 | + * @param {Partial<Mode>} mode | |
| 709 | + */ | |
| 710 | +const END_SAME_AS_BEGIN = function(mode) { | |
| 711 | + return Object.assign(mode, | |
| 712 | + { | |
| 713 | + /** @type {ModeCallback} */ | |
| 714 | + 'on:begin': (m, resp) => { resp.data._beginMatch = m[1]; }, | |
| 715 | + /** @type {ModeCallback} */ | |
| 716 | + 'on:end': (m, resp) => { if (resp.data._beginMatch !== m[1]) resp.ignoreMatch(); } | |
| 717 | + }); | |
| 718 | +}; | |
| 719 | + | |
| 720 | +var MODES = /*#__PURE__*/Object.freeze({ | |
| 721 | + __proto__: null, | |
| 722 | + APOS_STRING_MODE: APOS_STRING_MODE, | |
| 723 | + BACKSLASH_ESCAPE: BACKSLASH_ESCAPE, | |
| 724 | + BINARY_NUMBER_MODE: BINARY_NUMBER_MODE, | |
| 725 | + BINARY_NUMBER_RE: BINARY_NUMBER_RE, | |
| 726 | + COMMENT: COMMENT, | |
| 727 | + C_BLOCK_COMMENT_MODE: C_BLOCK_COMMENT_MODE, | |
| 728 | + C_LINE_COMMENT_MODE: C_LINE_COMMENT_MODE, | |
| 729 | + C_NUMBER_MODE: C_NUMBER_MODE, | |
| 730 | + C_NUMBER_RE: C_NUMBER_RE, | |
| 731 | + END_SAME_AS_BEGIN: END_SAME_AS_BEGIN, | |
| 732 | + HASH_COMMENT_MODE: HASH_COMMENT_MODE, | |
| 733 | + IDENT_RE: IDENT_RE, | |
| 734 | + MATCH_NOTHING_RE: MATCH_NOTHING_RE, | |
| 735 | + METHOD_GUARD: METHOD_GUARD, | |
| 736 | + NUMBER_MODE: NUMBER_MODE, | |
| 737 | + NUMBER_RE: NUMBER_RE, | |
| 738 | + PHRASAL_WORDS_MODE: PHRASAL_WORDS_MODE, | |
| 739 | + QUOTE_STRING_MODE: QUOTE_STRING_MODE, | |
| 740 | + REGEXP_MODE: REGEXP_MODE, | |
| 741 | + RE_STARTERS_RE: RE_STARTERS_RE, | |
| 742 | + SHEBANG: SHEBANG, | |
| 743 | + TITLE_MODE: TITLE_MODE, | |
| 744 | + UNDERSCORE_IDENT_RE: UNDERSCORE_IDENT_RE, | |
| 745 | + UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE | |
| 746 | +}); | |
| 747 | + | |
| 748 | +/** | |
| 749 | +@typedef {import('highlight.js').CallbackResponse} CallbackResponse | |
| 750 | +@typedef {import('highlight.js').CompilerExt} CompilerExt | |
| 751 | +*/ | |
| 752 | + | |
| 753 | +// Grammar extensions / plugins | |
| 754 | +// See: https://github.com/highlightjs/highlight.js/issues/2833 | |
| 755 | + | |
| 756 | +// Grammar extensions allow "syntactic sugar" to be added to the grammar modes | |
| 757 | +// without requiring any underlying changes to the compiler internals. | |
| 758 | + | |
| 759 | +// `compileMatch` being the perfect small example of now allowing a grammar | |
| 760 | +// author to write `match` when they desire to match a single expression rather | |
| 761 | +// than being forced to use `begin`. The extension then just moves `match` into | |
| 762 | +// `begin` when it runs. Ie, no features have been added, but we've just made | |
| 763 | +// the experience of writing (and reading grammars) a little bit nicer. | |
| 764 | + | |
| 765 | +// ------ | |
| 766 | + | |
| 767 | +// TODO: We need negative look-behind support to do this properly | |
| 768 | +/** | |
| 769 | + * Skip a match if it has a preceding dot | |
| 770 | + * | |
| 771 | + * This is used for `beginKeywords` to prevent matching expressions such as | |
| 772 | + * `bob.keyword.do()`. The mode compiler automatically wires this up as a | |
| 773 | + * special _internal_ 'on:begin' callback for modes with `beginKeywords` | |
| 774 | + * @param {RegExpMatchArray} match | |
| 775 | + * @param {CallbackResponse} response | |
| 776 | + */ | |
| 777 | +function skipIfHasPrecedingDot(match, response) { | |
| 778 | + const before = match.input[match.index - 1]; | |
| 779 | + if (before === ".") { | |
| 780 | + response.ignoreMatch(); | |
| 781 | + } | |
| 782 | +} | |
| 783 | + | |
| 784 | +/** | |
| 785 | + * | |
| 786 | + * @type {CompilerExt} | |
| 787 | + */ | |
| 788 | +function scopeClassName(mode, _parent) { | |
| 789 | + // eslint-disable-next-line no-undefined | |
| 790 | + if (mode.className !== undefined) { | |
| 791 | + mode.scope = mode.className; | |
| 792 | + delete mode.className; | |
| 793 | + } | |
| 794 | +} | |
| 795 | + | |
| 796 | +/** | |
| 797 | + * `beginKeywords` syntactic sugar | |
| 798 | + * @type {CompilerExt} | |
| 799 | + */ | |
| 800 | +function beginKeywords(mode, parent) { | |
| 801 | + if (!parent) return; | |
| 802 | + if (!mode.beginKeywords) return; | |
| 803 | + | |
| 804 | + // for languages with keywords that include non-word characters checking for | |
| 805 | + // a word boundary is not sufficient, so instead we check for a word boundary | |
| 806 | + // or whitespace - this does no harm in any case since our keyword engine | |
| 807 | + // doesn't allow spaces in keywords anyways and we still check for the boundary | |
| 808 | + // first | |
| 809 | + mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\.)(?=\\b|\\s)'; | |
| 810 | + mode.__beforeBegin = skipIfHasPrecedingDot; | |
| 811 | + mode.keywords = mode.keywords || mode.beginKeywords; | |
| 812 | + delete mode.beginKeywords; | |
| 813 | + | |
| 814 | + // prevents double relevance, the keywords themselves provide | |
| 815 | + // relevance, the mode doesn't need to double it | |
| 816 | + // eslint-disable-next-line no-undefined | |
| 817 | + if (mode.relevance === undefined) mode.relevance = 0; | |
| 818 | +} | |
| 819 | + | |
| 820 | +/** | |
| 821 | + * Allow `illegal` to contain an array of illegal values | |
| 822 | + * @type {CompilerExt} | |
| 823 | + */ | |
| 824 | +function compileIllegal(mode, _parent) { | |
| 825 | + if (!Array.isArray(mode.illegal)) return; | |
| 826 | + | |
| 827 | + mode.illegal = either(...mode.illegal); | |
| 828 | +} | |
| 829 | + | |
| 830 | +/** | |
| 831 | + * `match` to match a single expression for readability | |
| 832 | + * @type {CompilerExt} | |
| 833 | + */ | |
| 834 | +function compileMatch(mode, _parent) { | |
| 835 | + if (!mode.match) return; | |
| 836 | + if (mode.begin || mode.end) throw new Error("begin & end are not supported with match"); | |
| 837 | + | |
| 838 | + mode.begin = mode.match; | |
| 839 | + delete mode.match; | |
| 840 | +} | |
| 841 | + | |
| 842 | +/** | |
| 843 | + * provides the default 1 relevance to all modes | |
| 844 | + * @type {CompilerExt} | |
| 845 | + */ | |
| 846 | +function compileRelevance(mode, _parent) { | |
| 847 | + // eslint-disable-next-line no-undefined | |
| 848 | + if (mode.relevance === undefined) mode.relevance = 1; | |
| 849 | +} | |
| 850 | + | |
| 851 | +// allow beforeMatch to act as a "qualifier" for the match | |
| 852 | +// the full match begin must be [beforeMatch][begin] | |
| 853 | +const beforeMatchExt = (mode, parent) => { | |
| 854 | + if (!mode.beforeMatch) return; | |
| 855 | + // starts conflicts with endsParent which we need to make sure the child | |
| 856 | + // rule is not matched multiple times | |
| 857 | + if (mode.starts) throw new Error("beforeMatch cannot be used with starts"); | |
| 858 | + | |
| 859 | + const originalMode = Object.assign({}, mode); | |
| 860 | + Object.keys(mode).forEach((key) => { delete mode[key]; }); | |
| 861 | + | |
| 862 | + mode.keywords = originalMode.keywords; | |
| 863 | + mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin)); | |
| 864 | + mode.starts = { | |
| 865 | + relevance: 0, | |
| 866 | + contains: [ | |
| 867 | + Object.assign(originalMode, { endsParent: true }) | |
| 868 | + ] | |
| 869 | + }; | |
| 870 | + mode.relevance = 0; | |
| 871 | + | |
| 872 | + delete originalMode.beforeMatch; | |
| 873 | +}; | |
| 874 | + | |
| 875 | +// keywords that should have no default relevance value | |
| 876 | +const COMMON_KEYWORDS = [ | |
| 877 | + 'of', | |
| 878 | + 'and', | |
| 879 | + 'for', | |
| 880 | + 'in', | |
| 881 | + 'not', | |
| 882 | + 'or', | |
| 883 | + 'if', | |
| 884 | + 'then', | |
| 885 | + 'parent', // common variable name | |
| 886 | + 'list', // common variable name | |
| 887 | + 'value' // common variable name | |
| 888 | +]; | |
| 889 | + | |
| 890 | +const DEFAULT_KEYWORD_SCOPE = "keyword"; | |
| 891 | + | |
| 892 | +/** | |
| 893 | + * Given raw keywords from a language definition, compile them. | |
| 894 | + * | |
| 895 | + * @param {string | Record<string,string|string[]> | Array<string>} rawKeywords | |
| 896 | + * @param {boolean} caseInsensitive | |
| 897 | + */ | |
| 898 | +function compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) { | |
| 899 | + /** @type {import("highlight.js/private").KeywordDict} */ | |
| 900 | + const compiledKeywords = Object.create(null); | |
| 901 | + | |
| 902 | + // input can be a string of keywords, an array of keywords, or a object with | |
| 903 | + // named keys representing scopeName (which can then point to a string or array) | |
| 904 | + if (typeof rawKeywords === 'string') { | |
| 905 | + compileList(scopeName, rawKeywords.split(" ")); | |
| 906 | + } else if (Array.isArray(rawKeywords)) { | |
| 907 | + compileList(scopeName, rawKeywords); | |
| 908 | + } else { | |
| 909 | + Object.keys(rawKeywords).forEach(function(scopeName) { | |
| 910 | + // collapse all our objects back into the parent object | |
| 911 | + Object.assign( | |
| 912 | + compiledKeywords, | |
| 913 | + compileKeywords(rawKeywords[scopeName], caseInsensitive, scopeName) | |
| 914 | + ); | |
| 915 | + }); | |
| 916 | + } | |
| 917 | + return compiledKeywords; | |
| 918 | + | |
| 919 | + // --- | |
| 920 | + | |
| 921 | + /** | |
| 922 | + * Compiles an individual list of keywords | |
| 923 | + * | |
| 924 | + * Ex: "for if when while|5" | |
| 925 | + * | |
| 926 | + * @param {string} scopeName | |
| 927 | + * @param {Array<string>} keywordList | |
| 928 | + */ | |
| 929 | + function compileList(scopeName, keywordList) { | |
| 930 | + if (caseInsensitive) { | |
| 931 | + keywordList = keywordList.map(x => x.toLowerCase()); | |
| 932 | + } | |
| 933 | + keywordList.forEach(function(keyword) { | |
| 934 | + const pair = keyword.split('|'); | |
| 935 | + compiledKeywords[pair[0]] = [scopeName, scoreForKeyword(pair[0], pair[1])]; | |
| 936 | + }); | |
| 937 | + } | |
| 938 | +} | |
| 939 | + | |
| 940 | +/** | |
| 941 | + * Returns the proper score for a given keyword | |
| 942 | + * | |
| 943 | + * Also takes into account comment keywords, which will be scored 0 UNLESS | |
| 944 | + * another score has been manually assigned. | |
| 945 | + * @param {string} keyword | |
| 946 | + * @param {string} [providedScore] | |
| 947 | + */ | |
| 948 | +function scoreForKeyword(keyword, providedScore) { | |
| 949 | + // manual scores always win over common keywords | |
| 950 | + // so you can force a score of 1 if you really insist | |
| 951 | + if (providedScore) { | |
| 952 | + return Number(providedScore); | |
| 953 | + } | |
| 954 | + | |
| 955 | + return commonKeyword(keyword) ? 0 : 1; | |
| 956 | +} | |
| 957 | + | |
| 958 | +/** | |
| 959 | + * Determines if a given keyword is common or not | |
| 960 | + * | |
| 961 | + * @param {string} keyword */ | |
| 962 | +function commonKeyword(keyword) { | |
| 963 | + return COMMON_KEYWORDS.includes(keyword.toLowerCase()); | |
| 964 | +} | |
| 965 | + | |
| 966 | +/* | |
| 967 | + | |
| 968 | +For the reasoning behind this please see: | |
| 969 | +https://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419 | |
| 970 | + | |
| 971 | +*/ | |
| 972 | + | |
| 973 | +/** | |
| 974 | + * @type {Record<string, boolean>} | |
| 975 | + */ | |
| 976 | +const seenDeprecations = {}; | |
| 977 | + | |
| 978 | +/** | |
| 979 | + * @param {string} message | |
| 980 | + */ | |
| 981 | +const error = (message) => { | |
| 982 | + console.error(message); | |
| 983 | +}; | |
| 984 | + | |
| 985 | +/** | |
| 986 | + * @param {string} message | |
| 987 | + * @param {any} args | |
| 988 | + */ | |
| 989 | +const warn = (message, ...args) => { | |
| 990 | + console.log(`WARN: ${message}`, ...args); | |
| 991 | +}; | |
| 992 | + | |
| 993 | +/** | |
| 994 | + * @param {string} version | |
| 995 | + * @param {string} message | |
| 996 | + */ | |
| 997 | +const deprecated = (version, message) => { | |
| 998 | + if (seenDeprecations[`${version}/${message}`]) return; | |
| 999 | + | |
| 1000 | + console.log(`Deprecated as of ${version}. ${message}`); | |
| 1001 | + seenDeprecations[`${version}/${message}`] = true; | |
| 1002 | +}; | |
| 1003 | + | |
| 1004 | +/* eslint-disable no-throw-literal */ | |
| 1005 | + | |
| 1006 | +/** | |
| 1007 | +@typedef {import('highlight.js').CompiledMode} CompiledMode | |
| 1008 | +*/ | |
| 1009 | + | |
| 1010 | +const MultiClassError = new Error(); | |
| 1011 | + | |
| 1012 | +/** | |
| 1013 | + * Renumbers labeled scope names to account for additional inner match | |
| 1014 | + * groups that otherwise would break everything. | |
| 1015 | + * | |
| 1016 | + * Lets say we 3 match scopes: | |
| 1017 | + * | |
| 1018 | + * { 1 => ..., 2 => ..., 3 => ... } | |
| 1019 | + * | |
| 1020 | + * So what we need is a clean match like this: | |
| 1021 | + * | |
| 1022 | + * (a)(b)(c) => [ "a", "b", "c" ] | |
| 1023 | + * | |
| 1024 | + * But this falls apart with inner match groups: | |
| 1025 | + * | |
| 1026 | + * (a)(((b)))(c) => ["a", "b", "b", "b", "c" ] | |
| 1027 | + * | |
| 1028 | + * Our scopes are now "out of alignment" and we're repeating `b` 3 times. | |
| 1029 | + * What needs to happen is the numbers are remapped: | |
| 1030 | + * | |
| 1031 | + * { 1 => ..., 2 => ..., 5 => ... } | |
| 1032 | + * | |
| 1033 | + * We also need to know that the ONLY groups that should be output | |
| 1034 | + * are 1, 2, and 5. This function handles this behavior. | |
| 1035 | + * | |
| 1036 | + * @param {CompiledMode} mode | |
| 1037 | + * @param {Array<RegExp | string>} regexes | |
| 1038 | + * @param {{key: "beginScope"|"endScope"}} opts | |
| 1039 | + */ | |
| 1040 | +function remapScopeNames(mode, regexes, { key }) { | |
| 1041 | + let offset = 0; | |
| 1042 | + const scopeNames = mode[key]; | |
| 1043 | + /** @type Record<number,boolean> */ | |
| 1044 | + const emit = {}; | |
| 1045 | + /** @type Record<number,string> */ | |
| 1046 | + const positions = {}; | |
| 1047 | + | |
| 1048 | + for (let i = 1; i <= regexes.length; i++) { | |
| 1049 | + positions[i + offset] = scopeNames[i]; | |
| 1050 | + emit[i + offset] = true; | |
| 1051 | + offset += countMatchGroups(regexes[i - 1]); | |
| 1052 | + } | |
| 1053 | + // we use _emit to keep track of which match groups are "top-level" to avoid double | |
| 1054 | + // output from inside match groups | |
| 1055 | + mode[key] = positions; | |
| 1056 | + mode[key]._emit = emit; | |
| 1057 | + mode[key]._multi = true; | |
| 1058 | +} | |
| 1059 | + | |
| 1060 | +/** | |
| 1061 | + * @param {CompiledMode} mode | |
| 1062 | + */ | |
| 1063 | +function beginMultiClass(mode) { | |
| 1064 | + if (!Array.isArray(mode.begin)) return; | |
| 1065 | + | |
| 1066 | + if (mode.skip || mode.excludeBegin || mode.returnBegin) { | |
| 1067 | + error("skip, excludeBegin, returnBegin not compatible with beginScope: {}"); | |
| 1068 | + throw MultiClassError; | |
| 1069 | + } | |
| 1070 | + | |
| 1071 | + if (typeof mode.beginScope !== "object" || mode.beginScope === null) { | |
| 1072 | + error("beginScope must be object"); | |
| 1073 | + throw MultiClassError; | |
| 1074 | + } | |
| 1075 | + | |
| 1076 | + remapScopeNames(mode, mode.begin, { key: "beginScope" }); | |
| 1077 | + mode.begin = _rewriteBackreferences(mode.begin, { joinWith: "" }); | |
| 1078 | +} | |
| 1079 | + | |
| 1080 | +/** | |
| 1081 | + * @param {CompiledMode} mode | |
| 1082 | + */ | |
| 1083 | +function endMultiClass(mode) { | |
| 1084 | + if (!Array.isArray(mode.end)) return; | |
| 1085 | + | |
| 1086 | + if (mode.skip || mode.excludeEnd || mode.returnEnd) { | |
| 1087 | + error("skip, excludeEnd, returnEnd not compatible with endScope: {}"); | |
| 1088 | + throw MultiClassError; | |
| 1089 | + } | |
| 1090 | + | |
| 1091 | + if (typeof mode.endScope !== "object" || mode.endScope === null) { | |
| 1092 | + error("endScope must be object"); | |
| 1093 | + throw MultiClassError; | |
| 1094 | + } | |
| 1095 | + | |
| 1096 | + remapScopeNames(mode, mode.end, { key: "endScope" }); | |
| 1097 | + mode.end = _rewriteBackreferences(mode.end, { joinWith: "" }); | |
| 1098 | +} | |
| 1099 | + | |
| 1100 | +/** | |
| 1101 | + * this exists only to allow `scope: {}` to be used beside `match:` | |
| 1102 | + * Otherwise `beginScope` would necessary and that would look weird | |
| 1103 | + | |
| 1104 | + { | |
| 1105 | + match: [ /def/, /\w+/ ] | |
| 1106 | + scope: { 1: "keyword" , 2: "title" } | |
| 1107 | + } | |
| 1108 | + | |
| 1109 | + * @param {CompiledMode} mode | |
| 1110 | + */ | |
| 1111 | +function scopeSugar(mode) { | |
| 1112 | + if (mode.scope && typeof mode.scope === "object" && mode.scope !== null) { | |
| 1113 | + mode.beginScope = mode.scope; | |
| 1114 | + delete mode.scope; | |
| 1115 | + } | |
| 1116 | +} | |
| 1117 | + | |
| 1118 | +/** | |
| 1119 | + * @param {CompiledMode} mode | |
| 1120 | + */ | |
| 1121 | +function MultiClass(mode) { | |
| 1122 | + scopeSugar(mode); | |
| 1123 | + | |
| 1124 | + if (typeof mode.beginScope === "string") { | |
| 1125 | + mode.beginScope = { _wrap: mode.beginScope }; | |
| 1126 | + } | |
| 1127 | + if (typeof mode.endScope === "string") { | |
| 1128 | + mode.endScope = { _wrap: mode.endScope }; | |
| 1129 | + } | |
| 1130 | + | |
| 1131 | + beginMultiClass(mode); | |
| 1132 | + endMultiClass(mode); | |
| 1133 | +} | |
| 1134 | + | |
| 1135 | +/** | |
| 1136 | +@typedef {import('highlight.js').Mode} Mode | |
| 1137 | +@typedef {import('highlight.js').CompiledMode} CompiledMode | |
| 1138 | +@typedef {import('highlight.js').Language} Language | |
| 1139 | +@typedef {import('highlight.js').HLJSPlugin} HLJSPlugin | |
| 1140 | +@typedef {import('highlight.js').CompiledLanguage} CompiledLanguage | |
| 1141 | +*/ | |
| 1142 | + | |
| 1143 | +// compilation | |
| 1144 | + | |
| 1145 | +/** | |
| 1146 | + * Compiles a language definition result | |
| 1147 | + * | |
| 1148 | + * Given the raw result of a language definition (Language), compiles this so | |
| 1149 | + * that it is ready for highlighting code. | |
| 1150 | + * @param {Language} language | |
| 1151 | + * @returns {CompiledLanguage} | |
| 1152 | + */ | |
| 1153 | +function compileLanguage(language) { | |
| 1154 | + /** | |
| 1155 | + * Builds a regex with the case sensitivity of the current language | |
| 1156 | + * | |
| 1157 | + * @param {RegExp | string} value | |
| 1158 | + * @param {boolean} [global] | |
| 1159 | + */ | |
| 1160 | + function langRe(value, global) { | |
| 1161 | + return new RegExp( | |
| 1162 | + source(value), | |
| 1163 | + 'm' | |
| 1164 | + + (language.case_insensitive ? 'i' : '') | |
| 1165 | + + (language.unicodeRegex ? 'u' : '') | |
| 1166 | + + (global ? 'g' : '') | |
| 1167 | + ); | |
| 1168 | + } | |
| 1169 | + | |
| 1170 | + /** | |
| 1171 | + Stores multiple regular expressions and allows you to quickly search for | |
| 1172 | + them all in a string simultaneously - returning the first match. It does | |
| 1173 | + this by creating a huge (a|b|c) regex - each individual item wrapped with () | |
| 1174 | + and joined by `|` - using match groups to track position. When a match is | |
| 1175 | + found checking which position in the array has content allows us to figure | |
| 1176 | + out which of the original regexes / match groups triggered the match. | |
| 1177 | + | |
| 1178 | + The match object itself (the result of `Regex.exec`) is returned but also | |
| 1179 | + enhanced by merging in any meta-data that was registered with the regex. | |
| 1180 | + This is how we keep track of which mode matched, and what type of rule | |
| 1181 | + (`illegal`, `begin`, end, etc). | |
| 1182 | + */ | |
| 1183 | + class MultiRegex { | |
| 1184 | + constructor() { | |
| 1185 | + this.matchIndexes = {}; | |
| 1186 | + // @ts-ignore | |
| 1187 | + this.regexes = []; | |
| 1188 | + this.matchAt = 1; | |
| 1189 | + this.position = 0; | |
| 1190 | + } | |
| 1191 | + | |
| 1192 | + // @ts-ignore | |
| 1193 | + addRule(re, opts) { | |
| 1194 | + opts.position = this.position++; | |
| 1195 | + // @ts-ignore | |
| 1196 | + this.matchIndexes[this.matchAt] = opts; | |
| 1197 | + this.regexes.push([opts, re]); | |
| 1198 | + this.matchAt += countMatchGroups(re) + 1; | |
| 1199 | + } | |
| 1200 | + | |
| 1201 | + compile() { | |
| 1202 | + if (this.regexes.length === 0) { | |
| 1203 | + // avoids the need to check length every time exec is called | |
| 1204 | + // @ts-ignore | |
| 1205 | + this.exec = () => null; | |
| 1206 | + } | |
| 1207 | + const terminators = this.regexes.map(el => el[1]); | |
| 1208 | + this.matcherRe = langRe(_rewriteBackreferences(terminators, { joinWith: '|' }), true); | |
| 1209 | + this.lastIndex = 0; | |
| 1210 | + } | |
| 1211 | + | |
| 1212 | + /** @param {string} s */ | |
| 1213 | + exec(s) { | |
| 1214 | + this.matcherRe.lastIndex = this.lastIndex; | |
| 1215 | + const match = this.matcherRe.exec(s); | |
| 1216 | + if (!match) { return null; } | |
| 1217 | + | |
| 1218 | + // eslint-disable-next-line no-undefined | |
| 1219 | + const i = match.findIndex((el, i) => i > 0 && el !== undefined); | |
| 1220 | + // @ts-ignore | |
| 1221 | + const matchData = this.matchIndexes[i]; | |
| 1222 | + // trim off any earlier non-relevant match groups (ie, the other regex | |
| 1223 | + // match groups that make up the multi-matcher) | |
| 1224 | + match.splice(0, i); | |
| 1225 | + | |
| 1226 | + return Object.assign(match, matchData); | |
| 1227 | + } | |
| 1228 | + } | |
| 1229 | + | |
| 1230 | + /* | |
| 1231 | + Created to solve the key deficiently with MultiRegex - there is no way to | |
| 1232 | + test for multiple matches at a single location. Why would we need to do | |
| 1233 | + that? In the future a more dynamic engine will allow certain matches to be | |
| 1234 | + ignored. An example: if we matched say the 3rd regex in a large group but | |
| 1235 | + decided to ignore it - we'd need to started testing again at the 4th | |
| 1236 | + regex... but MultiRegex itself gives us no real way to do that. | |
| 1237 | + | |
| 1238 | + So what this class creates MultiRegexs on the fly for whatever search | |
| 1239 | + position they are needed. | |
| 1240 | + | |
| 1241 | + NOTE: These additional MultiRegex objects are created dynamically. For most | |
| 1242 | + grammars most of the time we will never actually need anything more than the | |
| 1243 | + first MultiRegex - so this shouldn't have too much overhead. | |
| 1244 | + | |
| 1245 | + Say this is our search group, and we match regex3, but wish to ignore it. | |
| 1246 | + | |
| 1247 | + regex1 | regex2 | regex3 | regex4 | regex5 ' ie, startAt = 0 | |
| 1248 | + | |
| 1249 | + What we need is a new MultiRegex that only includes the remaining | |
| 1250 | + possibilities: | |
| 1251 | + | |
| 1252 | + regex4 | regex5 ' ie, startAt = 3 | |
| 1253 | + | |
| 1254 | + This class wraps all that complexity up in a simple API... `startAt` decides | |
| 1255 | + where in the array of expressions to start doing the matching. It | |
| 1256 | + auto-increments, so if a match is found at position 2, then startAt will be | |
| 1257 | + set to 3. If the end is reached startAt will return to 0. | |
| 1258 | + | |
| 1259 | + MOST of the time the parser will be setting startAt manually to 0. | |
| 1260 | + */ | |
| 1261 | + class ResumableMultiRegex { | |
| 1262 | + constructor() { | |
| 1263 | + // @ts-ignore | |
| 1264 | + this.rules = []; | |
| 1265 | + // @ts-ignore | |
| 1266 | + this.multiRegexes = []; | |
| 1267 | + this.count = 0; | |
| 1268 | + | |
| 1269 | + this.lastIndex = 0; | |
| 1270 | + this.regexIndex = 0; | |
| 1271 | + } | |
| 1272 | + | |
| 1273 | + // @ts-ignore | |
| 1274 | + getMatcher(index) { | |
| 1275 | + if (this.multiRegexes[index]) return this.multiRegexes[index]; | |
| 1276 | + | |
| 1277 | + const matcher = new MultiRegex(); | |
| 1278 | + this.rules.slice(index).forEach(([re, opts]) => matcher.addRule(re, opts)); | |
| 1279 | + matcher.compile(); | |
| 1280 | + this.multiRegexes[index] = matcher; | |
| 1281 | + return matcher; | |
| 1282 | + } | |
| 1283 | + | |
| 1284 | + resumingScanAtSamePosition() { | |
| 1285 | + return this.regexIndex !== 0; | |
| 1286 | + } | |
| 1287 | + | |
| 1288 | + considerAll() { | |
| 1289 | + this.regexIndex = 0; | |
| 1290 | + } | |
| 1291 | + | |
| 1292 | + // @ts-ignore | |
| 1293 | + addRule(re, opts) { | |
| 1294 | + this.rules.push([re, opts]); | |
| 1295 | + if (opts.type === "begin") this.count++; | |
| 1296 | + } | |
| 1297 | + | |
| 1298 | + /** @param {string} s */ | |
| 1299 | + exec(s) { | |
| 1300 | + const m = this.getMatcher(this.regexIndex); | |
| 1301 | + m.lastIndex = this.lastIndex; | |
| 1302 | + let result = m.exec(s); | |
| 1303 | + | |
| 1304 | + // The following is because we have no easy way to say "resume scanning at the | |
| 1305 | + // existing position but also skip the current rule ONLY". What happens is | |
| 1306 | + // all prior rules are also skipped which can result in matching the wrong | |
| 1307 | + // thing. Example of matching "booger": | |
| 1308 | + | |
| 1309 | + // our matcher is [string, "booger", number] | |
| 1310 | + // | |
| 1311 | + // ....booger.... | |
| 1312 | + | |
| 1313 | + // if "booger" is ignored then we'd really need a regex to scan from the | |
| 1314 | + // SAME position for only: [string, number] but ignoring "booger" (if it | |
| 1315 | + // was the first match), a simple resume would scan ahead who knows how | |
| 1316 | + // far looking only for "number", ignoring potential string matches (or | |
| 1317 | + // future "booger" matches that might be valid.) | |
| 1318 | + | |
| 1319 | + // So what we do: We execute two matchers, one resuming at the same | |
| 1320 | + // position, but the second full matcher starting at the position after: | |
| 1321 | + | |
| 1322 | + // /--- resume first regex match here (for [number]) | |
| 1323 | + // |/---- full match here for [string, "booger", number] | |
| 1324 | + // vv | |
| 1325 | + // ....booger.... | |
| 1326 | + | |
| 1327 | + // Which ever results in a match first is then used. So this 3-4 step | |
| 1328 | + // process essentially allows us to say "match at this position, excluding | |
| 1329 | + // a prior rule that was ignored". | |
| 1330 | + // | |
| 1331 | + // 1. Match "booger" first, ignore. Also proves that [string] does non match. | |
| 1332 | + // 2. Resume matching for [number] | |
| 1333 | + // 3. Match at index + 1 for [string, "booger", number] | |
| 1334 | + // 4. If #2 and #3 result in matches, which came first? | |
| 1335 | + if (this.resumingScanAtSamePosition()) { | |
| 1336 | + if (result && result.index === this.lastIndex) ; else { // use the second matcher result | |
| 1337 | + const m2 = this.getMatcher(0); | |
| 1338 | + m2.lastIndex = this.lastIndex + 1; | |
| 1339 | + result = m2.exec(s); | |
| 1340 | + } | |
| 1341 | + } | |
| 1342 | + | |
| 1343 | + if (result) { | |
| 1344 | + this.regexIndex += result.position + 1; | |
| 1345 | + if (this.regexIndex === this.count) { | |
| 1346 | + // wrap-around to considering all matches again | |
| 1347 | + this.considerAll(); | |
| 1348 | + } | |
| 1349 | + } | |
| 1350 | + | |
| 1351 | + return result; | |
| 1352 | + } | |
| 1353 | + } | |
| 1354 | + | |
| 1355 | + /** | |
| 1356 | + * Given a mode, builds a huge ResumableMultiRegex that can be used to walk | |
| 1357 | + * the content and find matches. | |
| 1358 | + * | |
| 1359 | + * @param {CompiledMode} mode | |
| 1360 | + * @returns {ResumableMultiRegex} | |
| 1361 | + */ | |
| 1362 | + function buildModeRegex(mode) { | |
| 1363 | + const mm = new ResumableMultiRegex(); | |
| 1364 | + | |
| 1365 | + mode.contains.forEach(term => mm.addRule(term.begin, { rule: term, type: "begin" })); | |
| 1366 | + | |
| 1367 | + if (mode.terminatorEnd) { | |
| 1368 | + mm.addRule(mode.terminatorEnd, { type: "end" }); | |
| 1369 | + } | |
| 1370 | + if (mode.illegal) { | |
| 1371 | + mm.addRule(mode.illegal, { type: "illegal" }); | |
| 1372 | + } | |
| 1373 | + | |
| 1374 | + return mm; | |
| 1375 | + } | |
| 1376 | + | |
| 1377 | + /** skip vs abort vs ignore | |
| 1378 | + * | |
| 1379 | + * @skip - The mode is still entered and exited normally (and contains rules apply), | |
| 1380 | + * but all content is held and added to the parent buffer rather than being | |
| 1381 | + * output when the mode ends. Mostly used with `sublanguage` to build up | |
| 1382 | + * a single large buffer than can be parsed by sublanguage. | |
| 1383 | + * | |
| 1384 | + * - The mode begin ands ends normally. | |
| 1385 | + * - Content matched is added to the parent mode buffer. | |
| 1386 | + * - The parser cursor is moved forward normally. | |
| 1387 | + * | |
| 1388 | + * @abort - A hack placeholder until we have ignore. Aborts the mode (as if it | |
| 1389 | + * never matched) but DOES NOT continue to match subsequent `contains` | |
| 1390 | + * modes. Abort is bad/suboptimal because it can result in modes | |
| 1391 | + * farther down not getting applied because an earlier rule eats the | |
| 1392 | + * content but then aborts. | |
| 1393 | + * | |
| 1394 | + * - The mode does not begin. | |
| 1395 | + * - Content matched by `begin` is added to the mode buffer. | |
| 1396 | + * - The parser cursor is moved forward accordingly. | |
| 1397 | + * | |
| 1398 | + * @ignore - Ignores the mode (as if it never matched) and continues to match any | |
| 1399 | + * subsequent `contains` modes. Ignore isn't technically possible with | |
| 1400 | + * the current parser implementation. | |
| 1401 | + * | |
| 1402 | + * - The mode does not begin. | |
| 1403 | + * - Content matched by `begin` is ignored. | |
| 1404 | + * - The parser cursor is not moved forward. | |
| 1405 | + */ | |
| 1406 | + | |
| 1407 | + /** | |
| 1408 | + * Compiles an individual mode | |
| 1409 | + * | |
| 1410 | + * This can raise an error if the mode contains certain detectable known logic | |
| 1411 | + * issues. | |
| 1412 | + * @param {Mode} mode | |
| 1413 | + * @param {CompiledMode | null} [parent] | |
| 1414 | + * @returns {CompiledMode | never} | |
| 1415 | + */ | |
| 1416 | + function compileMode(mode, parent) { | |
| 1417 | + const cmode = /** @type CompiledMode */ (mode); | |
| 1418 | + if (mode.isCompiled) return cmode; | |
| 1419 | + | |
| 1420 | + [ | |
| 1421 | + scopeClassName, | |
| 1422 | + // do this early so compiler extensions generally don't have to worry about | |
| 1423 | + // the distinction between match/begin | |
| 1424 | + compileMatch, | |
| 1425 | + MultiClass, | |
| 1426 | + beforeMatchExt | |
| 1427 | + ].forEach(ext => ext(mode, parent)); | |
| 1428 | + | |
| 1429 | + language.compilerExtensions.forEach(ext => ext(mode, parent)); | |
| 1430 | + | |
| 1431 | + // __beforeBegin is considered private API, internal use only | |
| 1432 | + mode.__beforeBegin = null; | |
| 1433 | + | |
| 1434 | + [ | |
| 1435 | + beginKeywords, | |
| 1436 | + // do this later so compiler extensions that come earlier have access to the | |
| 1437 | + // raw array if they wanted to perhaps manipulate it, etc. | |
| 1438 | + compileIllegal, | |
| 1439 | + // default to 1 relevance if not specified | |
| 1440 | + compileRelevance | |
| 1441 | + ].forEach(ext => ext(mode, parent)); | |
| 1442 | + | |
| 1443 | + mode.isCompiled = true; | |
| 1444 | + | |
| 1445 | + let keywordPattern = null; | |
| 1446 | + if (typeof mode.keywords === "object" && mode.keywords.$pattern) { | |
| 1447 | + // we need a copy because keywords might be compiled multiple times | |
| 1448 | + // so we can't go deleting $pattern from the original on the first | |
| 1449 | + // pass | |
| 1450 | + mode.keywords = Object.assign({}, mode.keywords); | |
| 1451 | + keywordPattern = mode.keywords.$pattern; | |
| 1452 | + delete mode.keywords.$pattern; | |
| 1453 | + } | |
| 1454 | + keywordPattern = keywordPattern || /\w+/; | |
| 1455 | + | |
| 1456 | + if (mode.keywords) { | |
| 1457 | + mode.keywords = compileKeywords(mode.keywords, language.case_insensitive); | |
| 1458 | + } | |
| 1459 | + | |
| 1460 | + cmode.keywordPatternRe = langRe(keywordPattern, true); | |
| 1461 | + | |
| 1462 | + if (parent) { | |
| 1463 | + if (!mode.begin) mode.begin = /\B|\b/; | |
| 1464 | + cmode.beginRe = langRe(cmode.begin); | |
| 1465 | + if (!mode.end && !mode.endsWithParent) mode.end = /\B|\b/; | |
| 1466 | + if (mode.end) cmode.endRe = langRe(cmode.end); | |
| 1467 | + cmode.terminatorEnd = source(cmode.end) || ''; | |
| 1468 | + if (mode.endsWithParent && parent.terminatorEnd) { | |
| 1469 | + cmode.terminatorEnd += (mode.end ? '|' : '') + parent.terminatorEnd; | |
| 1470 | + } | |
| 1471 | + } | |
| 1472 | + if (mode.illegal) cmode.illegalRe = langRe(/** @type {RegExp | string} */ (mode.illegal)); | |
| 1473 | + if (!mode.contains) mode.contains = []; | |
| 1474 | + | |
| 1475 | + mode.contains = [].concat(...mode.contains.map(function(c) { | |
| 1476 | + return expandOrCloneMode(c === 'self' ? mode : c); | |
| 1477 | + })); | |
| 1478 | + mode.contains.forEach(function(c) { compileMode(/** @type Mode */ (c), cmode); }); | |
| 1479 | + | |
| 1480 | + if (mode.starts) { | |
| 1481 | + compileMode(mode.starts, parent); | |
| 1482 | + } | |
| 1483 | + | |
| 1484 | + cmode.matcher = buildModeRegex(cmode); | |
| 1485 | + return cmode; | |
| 1486 | + } | |
| 1487 | + | |
| 1488 | + if (!language.compilerExtensions) language.compilerExtensions = []; | |
| 1489 | + | |
| 1490 | + // self is not valid at the top-level | |
| 1491 | + if (language.contains && language.contains.includes('self')) { | |
| 1492 | + throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation."); | |
| 1493 | + } | |
| 1494 | + | |
| 1495 | + // we need a null object, which inherit will guarantee | |
| 1496 | + language.classNameAliases = inherit$1(language.classNameAliases || {}); | |
| 1497 | + | |
| 1498 | + return compileMode(/** @type Mode */ (language)); | |
| 1499 | +} | |
| 1500 | + | |
| 1501 | +/** | |
| 1502 | + * Determines if a mode has a dependency on it's parent or not | |
| 1503 | + * | |
| 1504 | + * If a mode does have a parent dependency then often we need to clone it if | |
| 1505 | + * it's used in multiple places so that each copy points to the correct parent, | |
| 1506 | + * where-as modes without a parent can often safely be re-used at the bottom of | |
| 1507 | + * a mode chain. | |
| 1508 | + * | |
| 1509 | + * @param {Mode | null} mode | |
| 1510 | + * @returns {boolean} - is there a dependency on the parent? | |
| 1511 | + * */ | |
| 1512 | +function dependencyOnParent(mode) { | |
| 1513 | + if (!mode) return false; | |
| 1514 | + | |
| 1515 | + return mode.endsWithParent || dependencyOnParent(mode.starts); | |
| 1516 | +} | |
| 1517 | + | |
| 1518 | +/** | |
| 1519 | + * Expands a mode or clones it if necessary | |
| 1520 | + * | |
| 1521 | + * This is necessary for modes with parental dependenceis (see notes on | |
| 1522 | + * `dependencyOnParent`) and for nodes that have `variants` - which must then be | |
| 1523 | + * exploded into their own individual modes at compile time. | |
| 1524 | + * | |
| 1525 | + * @param {Mode} mode | |
| 1526 | + * @returns {Mode | Mode[]} | |
| 1527 | + * */ | |
| 1528 | +function expandOrCloneMode(mode) { | |
| 1529 | + if (mode.variants && !mode.cachedVariants) { | |
| 1530 | + mode.cachedVariants = mode.variants.map(function(variant) { | |
| 1531 | + return inherit$1(mode, { variants: null }, variant); | |
| 1532 | + }); | |
| 1533 | + } | |
| 1534 | + | |
| 1535 | + // EXPAND | |
| 1536 | + // if we have variants then essentially "replace" the mode with the variants | |
| 1537 | + // this happens in compileMode, where this function is called from | |
| 1538 | + if (mode.cachedVariants) { | |
| 1539 | + return mode.cachedVariants; | |
| 1540 | + } | |
| 1541 | + | |
| 1542 | + // CLONE | |
| 1543 | + // if we have dependencies on parents then we need a unique | |
| 1544 | + // instance of ourselves, so we can be reused with many | |
| 1545 | + // different parents without issue | |
| 1546 | + if (dependencyOnParent(mode)) { | |
| 1547 | + return inherit$1(mode, { starts: mode.starts ? inherit$1(mode.starts) : null }); | |
| 1548 | + } | |
| 1549 | + | |
| 1550 | + if (Object.isFrozen(mode)) { | |
| 1551 | + return inherit$1(mode); | |
| 1552 | + } | |
| 1553 | + | |
| 1554 | + // no special dependency issues, just return ourselves | |
| 1555 | + return mode; | |
| 1556 | +} | |
| 1557 | + | |
| 1558 | +var version = "11.11.1"; | |
| 1559 | + | |
| 1560 | +class HTMLInjectionError extends Error { | |
| 1561 | + constructor(reason, html) { | |
| 1562 | + super(reason); | |
| 1563 | + this.name = "HTMLInjectionError"; | |
| 1564 | + this.html = html; | |
| 1565 | + } | |
| 1566 | +} | |
| 1567 | + | |
| 1568 | +/* | |
| 1569 | +Syntax highlighting with language autodetection. | |
| 1570 | +https://highlightjs.org/ | |
| 1571 | +*/ | |
| 1572 | + | |
| 1573 | + | |
| 1574 | + | |
| 1575 | +/** | |
| 1576 | +@typedef {import('highlight.js').Mode} Mode | |
| 1577 | +@typedef {import('highlight.js').CompiledMode} CompiledMode | |
| 1578 | +@typedef {import('highlight.js').CompiledScope} CompiledScope | |
| 1579 | +@typedef {import('highlight.js').Language} Language | |
| 1580 | +@typedef {import('highlight.js').HLJSApi} HLJSApi | |
| 1581 | +@typedef {import('highlight.js').HLJSPlugin} HLJSPlugin | |
| 1582 | +@typedef {import('highlight.js').PluginEvent} PluginEvent | |
| 1583 | +@typedef {import('highlight.js').HLJSOptions} HLJSOptions | |
| 1584 | +@typedef {import('highlight.js').LanguageFn} LanguageFn | |
| 1585 | +@typedef {import('highlight.js').HighlightedHTMLElement} HighlightedHTMLElement | |
| 1586 | +@typedef {import('highlight.js').BeforeHighlightContext} BeforeHighlightContext | |
| 1587 | +@typedef {import('highlight.js/private').MatchType} MatchType | |
| 1588 | +@typedef {import('highlight.js/private').KeywordData} KeywordData | |
| 1589 | +@typedef {import('highlight.js/private').EnhancedMatch} EnhancedMatch | |
| 1590 | +@typedef {import('highlight.js/private').AnnotatedError} AnnotatedError | |
| 1591 | +@typedef {import('highlight.js').AutoHighlightResult} AutoHighlightResult | |
| 1592 | +@typedef {import('highlight.js').HighlightOptions} HighlightOptions | |
| 1593 | +@typedef {import('highlight.js').HighlightResult} HighlightResult | |
| 1594 | +*/ | |
| 1595 | + | |
| 1596 | + | |
| 1597 | +const escape = escapeHTML; | |
| 1598 | +const inherit = inherit$1; | |
| 1599 | +const NO_MATCH = Symbol("nomatch"); | |
| 1600 | +const MAX_KEYWORD_HITS = 7; | |
| 1601 | + | |
| 1602 | +/** | |
| 1603 | + * @param {any} hljs - object that is extended (legacy) | |
| 1604 | + * @returns {HLJSApi} | |
| 1605 | + */ | |
| 1606 | +const HLJS = function(hljs) { | |
| 1607 | + // Global internal variables used within the highlight.js library. | |
| 1608 | + /** @type {Record<string, Language>} */ | |
| 1609 | + const languages = Object.create(null); | |
| 1610 | + /** @type {Record<string, string>} */ | |
| 1611 | + const aliases = Object.create(null); | |
| 1612 | + /** @type {HLJSPlugin[]} */ | |
| 1613 | + const plugins = []; | |
| 1614 | + | |
| 1615 | + // safe/production mode - swallows more errors, tries to keep running | |
| 1616 | + // even if a single syntax or parse hits a fatal error | |
| 1617 | + let SAFE_MODE = true; | |
| 1618 | + const LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a language module?"; | |
| 1619 | + /** @type {Language} */ | |
| 1620 | + const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text', contains: [] }; | |
| 1621 | + | |
| 1622 | + // Global options used when within external APIs. This is modified when | |
| 1623 | + // calling the `hljs.configure` function. | |
| 1624 | + /** @type HLJSOptions */ | |
| 1625 | + let options = { | |
| 1626 | + ignoreUnescapedHTML: false, | |
| 1627 | + throwUnescapedHTML: false, | |
| 1628 | + noHighlightRe: /^(no-?highlight)$/i, | |
| 1629 | + languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i, | |
| 1630 | + classPrefix: 'hljs-', | |
| 1631 | + cssSelector: 'pre code', | |
| 1632 | + languages: null, | |
| 1633 | + // beta configuration options, subject to change, welcome to discuss | |
| 1634 | + // https://github.com/highlightjs/highlight.js/issues/1086 | |
| 1635 | + __emitter: TokenTreeEmitter | |
| 1636 | + }; | |
| 1637 | + | |
| 1638 | + /* Utility functions */ | |
| 1639 | + | |
| 1640 | + /** | |
| 1641 | + * Tests a language name to see if highlighting should be skipped | |
| 1642 | + * @param {string} languageName | |
| 1643 | + */ | |
| 1644 | + function shouldNotHighlight(languageName) { | |
| 1645 | + return options.noHighlightRe.test(languageName); | |
| 1646 | + } | |
| 1647 | + | |
| 1648 | + /** | |
| 1649 | + * @param {HighlightedHTMLElement} block - the HTML element to determine language for | |
| 1650 | + */ | |
| 1651 | + function blockLanguage(block) { | |
| 1652 | + let classes = block.className + ' '; | |
| 1653 | + | |
| 1654 | + classes += block.parentNode ? block.parentNode.className : ''; | |
| 1655 | + | |
| 1656 | + // language-* takes precedence over non-prefixed class names. | |
| 1657 | + const match = options.languageDetectRe.exec(classes); | |
| 1658 | + if (match) { | |
| 1659 | + const language = getLanguage(match[1]); | |
| 1660 | + if (!language) { | |
| 1661 | + warn(LANGUAGE_NOT_FOUND.replace("{}", match[1])); | |
| 1662 | + warn("Falling back to no-highlight mode for this block.", block); | |
| 1663 | + } | |
| 1664 | + return language ? match[1] : 'no-highlight'; | |
| 1665 | + } | |
| 1666 | + | |
| 1667 | + return classes | |
| 1668 | + .split(/\s+/) | |
| 1669 | + .find((_class) => shouldNotHighlight(_class) || getLanguage(_class)); | |
| 1670 | + } | |
| 1671 | + | |
| 1672 | + /** | |
| 1673 | + * Core highlighting function. | |
| 1674 | + * | |
| 1675 | + * OLD API | |
| 1676 | + * highlight(lang, code, ignoreIllegals, continuation) | |
| 1677 | + * | |
| 1678 | + * NEW API | |
| 1679 | + * highlight(code, {lang, ignoreIllegals}) | |
| 1680 | + * | |
| 1681 | + * @param {string} codeOrLanguageName - the language to use for highlighting | |
| 1682 | + * @param {string | HighlightOptions} optionsOrCode - the code to highlight | |
| 1683 | + * @param {boolean} [ignoreIllegals] - whether to ignore illegal matches, default is to bail | |
| 1684 | + * | |
| 1685 | + * @returns {HighlightResult} Result - an object that represents the result | |
| 1686 | + * @property {string} language - the language name | |
| 1687 | + * @property {number} relevance - the relevance score | |
| 1688 | + * @property {string} value - the highlighted HTML code | |
| 1689 | + * @property {string} code - the original raw code | |
| 1690 | + * @property {CompiledMode} top - top of the current mode stack | |
| 1691 | + * @property {boolean} illegal - indicates whether any illegal matches were found | |
| 1692 | + */ | |
| 1693 | + function highlight(codeOrLanguageName, optionsOrCode, ignoreIllegals) { | |
| 1694 | + let code = ""; | |
| 1695 | + let languageName = ""; | |
| 1696 | + if (typeof optionsOrCode === "object") { | |
| 1697 | + code = codeOrLanguageName; | |
| 1698 | + ignoreIllegals = optionsOrCode.ignoreIllegals; | |
| 1699 | + languageName = optionsOrCode.language; | |
| 1700 | + } else { | |
| 1701 | + // old API | |
| 1702 | + deprecated("10.7.0", "highlight(lang, code, ...args) has been deprecated."); | |
| 1703 | + deprecated("10.7.0", "Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"); | |
| 1704 | + languageName = codeOrLanguageName; | |
| 1705 | + code = optionsOrCode; | |
| 1706 | + } | |
| 1707 | + | |
| 1708 | + // https://github.com/highlightjs/highlight.js/issues/3149 | |
| 1709 | + // eslint-disable-next-line no-undefined | |
| 1710 | + if (ignoreIllegals === undefined) { ignoreIllegals = true; } | |
| 1711 | + | |
| 1712 | + /** @type {BeforeHighlightContext} */ | |
| 1713 | + const context = { | |
| 1714 | + code, | |
| 1715 | + language: languageName | |
| 1716 | + }; | |
| 1717 | + // the plugin can change the desired language or the code to be highlighted | |
| 1718 | + // just be changing the object it was passed | |
| 1719 | + fire("before:highlight", context); | |
| 1720 | + | |
| 1721 | + // a before plugin can usurp the result completely by providing it's own | |
| 1722 | + // in which case we don't even need to call highlight | |
| 1723 | + const result = context.result | |
| 1724 | + ? context.result | |
| 1725 | + : _highlight(context.language, context.code, ignoreIllegals); | |
| 1726 | + | |
| 1727 | + result.code = context.code; | |
| 1728 | + // the plugin can change anything in result to suite it | |
| 1729 | + fire("after:highlight", result); | |
| 1730 | + | |
| 1731 | + return result; | |
| 1732 | + } | |
| 1733 | + | |
| 1734 | + /** | |
| 1735 | + * private highlight that's used internally and does not fire callbacks | |
| 1736 | + * | |
| 1737 | + * @param {string} languageName - the language to use for highlighting | |
| 1738 | + * @param {string} codeToHighlight - the code to highlight | |
| 1739 | + * @param {boolean?} [ignoreIllegals] - whether to ignore illegal matches, default is to bail | |
| 1740 | + * @param {CompiledMode?} [continuation] - current continuation mode, if any | |
| 1741 | + * @returns {HighlightResult} - result of the highlight operation | |
| 1742 | + */ | |
| 1743 | + function _highlight(languageName, codeToHighlight, ignoreIllegals, continuation) { | |
| 1744 | + const keywordHits = Object.create(null); | |
| 1745 | + | |
| 1746 | + /** | |
| 1747 | + * Return keyword data if a match is a keyword | |
| 1748 | + * @param {CompiledMode} mode - current mode | |
| 1749 | + * @param {string} matchText - the textual match | |
| 1750 | + * @returns {KeywordData | false} | |
| 1751 | + */ | |
| 1752 | + function keywordData(mode, matchText) { | |
| 1753 | + return mode.keywords[matchText]; | |
| 1754 | + } | |
| 1755 | + | |
| 1756 | + function processKeywords() { | |
| 1757 | + if (!top.keywords) { | |
| 1758 | + emitter.addText(modeBuffer); | |
| 1759 | + return; | |
| 1760 | + } | |
| 1761 | + | |
| 1762 | + let lastIndex = 0; | |
| 1763 | + top.keywordPatternRe.lastIndex = 0; | |
| 1764 | + let match = top.keywordPatternRe.exec(modeBuffer); | |
| 1765 | + let buf = ""; | |
| 1766 | + | |
| 1767 | + while (match) { | |
| 1768 | + buf += modeBuffer.substring(lastIndex, match.index); | |
| 1769 | + const word = language.case_insensitive ? match[0].toLowerCase() : match[0]; | |
| 1770 | + const data = keywordData(top, word); | |
| 1771 | + if (data) { | |
| 1772 | + const [kind, keywordRelevance] = data; | |
| 1773 | + emitter.addText(buf); | |
| 1774 | + buf = ""; | |
| 1775 | + | |
| 1776 | + keywordHits[word] = (keywordHits[word] || 0) + 1; | |
| 1777 | + if (keywordHits[word] <= MAX_KEYWORD_HITS) relevance += keywordRelevance; | |
| 1778 | + if (kind.startsWith("_")) { | |
| 1779 | + // _ implied for relevance only, do not highlight | |
| 1780 | + // by applying a class name | |
| 1781 | + buf += match[0]; | |
| 1782 | + } else { | |
| 1783 | + const cssClass = language.classNameAliases[kind] || kind; | |
| 1784 | + emitKeyword(match[0], cssClass); | |
| 1785 | + } | |
| 1786 | + } else { | |
| 1787 | + buf += match[0]; | |
| 1788 | + } | |
| 1789 | + lastIndex = top.keywordPatternRe.lastIndex; | |
| 1790 | + match = top.keywordPatternRe.exec(modeBuffer); | |
| 1791 | + } | |
| 1792 | + buf += modeBuffer.substring(lastIndex); | |
| 1793 | + emitter.addText(buf); | |
| 1794 | + } | |
| 1795 | + | |
| 1796 | + function processSubLanguage() { | |
| 1797 | + if (modeBuffer === "") return; | |
| 1798 | + /** @type HighlightResult */ | |
| 1799 | + let result = null; | |
| 1800 | + | |
| 1801 | + if (typeof top.subLanguage === 'string') { | |
| 1802 | + if (!languages[top.subLanguage]) { | |
| 1803 | + emitter.addText(modeBuffer); | |
| 1804 | + return; | |
| 1805 | + } | |
| 1806 | + result = _highlight(top.subLanguage, modeBuffer, true, continuations[top.subLanguage]); | |
| 1807 | + continuations[top.subLanguage] = /** @type {CompiledMode} */ (result._top); | |
| 1808 | + } else { | |
| 1809 | + result = highlightAuto(modeBuffer, top.subLanguage.length ? top.subLanguage : null); | |
| 1810 | + } | |
| 1811 | + | |
| 1812 | + // Counting embedded language score towards the host language may be disabled | |
| 1813 | + // with zeroing the containing mode relevance. Use case in point is Markdown that | |
| 1814 | + // allows XML everywhere and makes every XML snippet to have a much larger Markdown | |
| 1815 | + // score. | |
| 1816 | + if (top.relevance > 0) { | |
| 1817 | + relevance += result.relevance; | |
| 1818 | + } | |
| 1819 | + emitter.__addSublanguage(result._emitter, result.language); | |
| 1820 | + } | |
| 1821 | + | |
| 1822 | + function processBuffer() { | |
| 1823 | + if (top.subLanguage != null) { | |
| 1824 | + processSubLanguage(); | |
| 1825 | + } else { | |
| 1826 | + processKeywords(); | |
| 1827 | + } | |
| 1828 | + modeBuffer = ''; | |
| 1829 | + } | |
| 1830 | + | |
| 1831 | + /** | |
| 1832 | + * @param {string} text | |
| 1833 | + * @param {string} scope | |
| 1834 | + */ | |
| 1835 | + function emitKeyword(keyword, scope) { | |
| 1836 | + if (keyword === "") return; | |
| 1837 | + | |
| 1838 | + emitter.startScope(scope); | |
| 1839 | + emitter.addText(keyword); | |
| 1840 | + emitter.endScope(); | |
| 1841 | + } | |
| 1842 | + | |
| 1843 | + /** | |
| 1844 | + * @param {CompiledScope} scope | |
| 1845 | + * @param {RegExpMatchArray} match | |
| 1846 | + */ | |
| 1847 | + function emitMultiClass(scope, match) { | |
| 1848 | + let i = 1; | |
| 1849 | + const max = match.length - 1; | |
| 1850 | + while (i <= max) { | |
| 1851 | + if (!scope._emit[i]) { i++; continue; } | |
| 1852 | + const klass = language.classNameAliases[scope[i]] || scope[i]; | |
| 1853 | + const text = match[i]; | |
| 1854 | + if (klass) { | |
| 1855 | + emitKeyword(text, klass); | |
| 1856 | + } else { | |
| 1857 | + modeBuffer = text; | |
| 1858 | + processKeywords(); | |
| 1859 | + modeBuffer = ""; | |
| 1860 | + } | |
| 1861 | + i++; | |
| 1862 | + } | |
| 1863 | + } | |
| 1864 | + | |
| 1865 | + /** | |
| 1866 | + * @param {CompiledMode} mode - new mode to start | |
| 1867 | + * @param {RegExpMatchArray} match | |
| 1868 | + */ | |
| 1869 | + function startNewMode(mode, match) { | |
| 1870 | + if (mode.scope && typeof mode.scope === "string") { | |
| 1871 | + emitter.openNode(language.classNameAliases[mode.scope] || mode.scope); | |
| 1872 | + } | |
| 1873 | + if (mode.beginScope) { | |
| 1874 | + // beginScope just wraps the begin match itself in a scope | |
| 1875 | + if (mode.beginScope._wrap) { | |
| 1876 | + emitKeyword(modeBuffer, language.classNameAliases[mode.beginScope._wrap] || mode.beginScope._wrap); | |
| 1877 | + modeBuffer = ""; | |
| 1878 | + } else if (mode.beginScope._multi) { | |
| 1879 | + // at this point modeBuffer should just be the match | |
| 1880 | + emitMultiClass(mode.beginScope, match); | |
| 1881 | + modeBuffer = ""; | |
| 1882 | + } | |
| 1883 | + } | |
| 1884 | + | |
| 1885 | + top = Object.create(mode, { parent: { value: top } }); | |
| 1886 | + return top; | |
| 1887 | + } | |
| 1888 | + | |
| 1889 | + /** | |
| 1890 | + * @param {CompiledMode } mode - the mode to potentially end | |
| 1891 | + * @param {RegExpMatchArray} match - the latest match | |
| 1892 | + * @param {string} matchPlusRemainder - match plus remainder of content | |
| 1893 | + * @returns {CompiledMode | void} - the next mode, or if void continue on in current mode | |
| 1894 | + */ | |
| 1895 | + function endOfMode(mode, match, matchPlusRemainder) { | |
| 1896 | + let matched = startsWith(mode.endRe, matchPlusRemainder); | |
| 1897 | + | |
| 1898 | + if (matched) { | |
| 1899 | + if (mode["on:end"]) { | |
| 1900 | + const resp = new Response(mode); | |
| 1901 | + mode["on:end"](match, resp); | |
| 1902 | + if (resp.isMatchIgnored) matched = false; | |
| 1903 | + } | |
| 1904 | + | |
| 1905 | + if (matched) { | |
| 1906 | + while (mode.endsParent && mode.parent) { | |
| 1907 | + mode = mode.parent; | |
| 1908 | + } | |
| 1909 | + return mode; | |
| 1910 | + } | |
| 1911 | + } | |
| 1912 | + // even if on:end fires an `ignore` it's still possible | |
| 1913 | + // that we might trigger the end node because of a parent mode | |
| 1914 | + if (mode.endsWithParent) { | |
| 1915 | + return endOfMode(mode.parent, match, matchPlusRemainder); | |
| 1916 | + } | |
| 1917 | + } | |
| 1918 | + | |
| 1919 | + /** | |
| 1920 | + * Handle matching but then ignoring a sequence of text | |
| 1921 | + * | |
| 1922 | + * @param {string} lexeme - string containing full match text | |
| 1923 | + */ | |
| 1924 | + function doIgnore(lexeme) { | |
| 1925 | + if (top.matcher.regexIndex === 0) { | |
| 1926 | + // no more regexes to potentially match here, so we move the cursor forward one | |
| 1927 | + // space | |
| 1928 | + modeBuffer += lexeme[0]; | |
| 1929 | + return 1; | |
| 1930 | + } else { | |
| 1931 | + // no need to move the cursor, we still have additional regexes to try and | |
| 1932 | + // match at this very spot | |
| 1933 | + resumeScanAtSamePosition = true; | |
| 1934 | + return 0; | |
| 1935 | + } | |
| 1936 | + } | |
| 1937 | + | |
| 1938 | + /** | |
| 1939 | + * Handle the start of a new potential mode match | |
| 1940 | + * | |
| 1941 | + * @param {EnhancedMatch} match - the current match | |
| 1942 | + * @returns {number} how far to advance the parse cursor | |
| 1943 | + */ | |
| 1944 | + function doBeginMatch(match) { | |
| 1945 | + const lexeme = match[0]; | |
| 1946 | + const newMode = match.rule; | |
| 1947 | + | |
| 1948 | + const resp = new Response(newMode); | |
| 1949 | + // first internal before callbacks, then the public ones | |
| 1950 | + const beforeCallbacks = [newMode.__beforeBegin, newMode["on:begin"]]; | |
| 1951 | + for (const cb of beforeCallbacks) { | |
| 1952 | + if (!cb) continue; | |
| 1953 | + cb(match, resp); | |
| 1954 | + if (resp.isMatchIgnored) return doIgnore(lexeme); | |
| 1955 | + } | |
| 1956 | + | |
| 1957 | + if (newMode.skip) { | |
| 1958 | + modeBuffer += lexeme; | |
| 1959 | + } else { | |
| 1960 | + if (newMode.excludeBegin) { | |
| 1961 | + modeBuffer += lexeme; | |
| 1962 | + } | |
| 1963 | + processBuffer(); | |
| 1964 | + if (!newMode.returnBegin && !newMode.excludeBegin) { | |
| 1965 | + modeBuffer = lexeme; | |
| 1966 | + } | |
| 1967 | + } | |
| 1968 | + startNewMode(newMode, match); | |
| 1969 | + return newMode.returnBegin ? 0 : lexeme.length; | |
| 1970 | + } | |
| 1971 | + | |
| 1972 | + /** | |
| 1973 | + * Handle the potential end of mode | |
| 1974 | + * | |
| 1975 | + * @param {RegExpMatchArray} match - the current match | |
| 1976 | + */ | |
| 1977 | + function doEndMatch(match) { | |
| 1978 | + const lexeme = match[0]; | |
| 1979 | + const matchPlusRemainder = codeToHighlight.substring(match.index); | |
| 1980 | + | |
| 1981 | + const endMode = endOfMode(top, match, matchPlusRemainder); | |
| 1982 | + if (!endMode) { return NO_MATCH; } | |
| 1983 | + | |
| 1984 | + const origin = top; | |
| 1985 | + if (top.endScope && top.endScope._wrap) { | |
| 1986 | + processBuffer(); | |
| 1987 | + emitKeyword(lexeme, top.endScope._wrap); | |
| 1988 | + } else if (top.endScope && top.endScope._multi) { | |
| 1989 | + processBuffer(); | |
| 1990 | + emitMultiClass(top.endScope, match); | |
| 1991 | + } else if (origin.skip) { | |
| 1992 | + modeBuffer += lexeme; | |
| 1993 | + } else { | |
| 1994 | + if (!(origin.returnEnd || origin.excludeEnd)) { | |
| 1995 | + modeBuffer += lexeme; | |
| 1996 | + } | |
| 1997 | + processBuffer(); | |
| 1998 | + if (origin.excludeEnd) { | |
| 1999 | + modeBuffer = lexeme; | |
| 2000 | + } | |
| 2001 | + } | |
| 2002 | + do { | |
| 2003 | + if (top.scope) { | |
| 2004 | + emitter.closeNode(); | |
| 2005 | + } | |
| 2006 | + if (!top.skip && !top.subLanguage) { | |
| 2007 | + relevance += top.relevance; | |
| 2008 | + } | |
| 2009 | + top = top.parent; | |
| 2010 | + } while (top !== endMode.parent); | |
| 2011 | + if (endMode.starts) { | |
| 2012 | + startNewMode(endMode.starts, match); | |
| 2013 | + } | |
| 2014 | + return origin.returnEnd ? 0 : lexeme.length; | |
| 2015 | + } | |
| 2016 | + | |
| 2017 | + function processContinuations() { | |
| 2018 | + const list = []; | |
| 2019 | + for (let current = top; current !== language; current = current.parent) { | |
| 2020 | + if (current.scope) { | |
| 2021 | + list.unshift(current.scope); | |
| 2022 | + } | |
| 2023 | + } | |
| 2024 | + list.forEach(item => emitter.openNode(item)); | |
| 2025 | + } | |
| 2026 | + | |
| 2027 | + /** @type {{type?: MatchType, index?: number, rule?: Mode}}} */ | |
| 2028 | + let lastMatch = {}; | |
| 2029 | + | |
| 2030 | + /** | |
| 2031 | + * Process an individual match | |
| 2032 | + * | |
| 2033 | + * @param {string} textBeforeMatch - text preceding the match (since the last match) | |
| 2034 | + * @param {EnhancedMatch} [match] - the match itself | |
| 2035 | + */ | |
| 2036 | + function processLexeme(textBeforeMatch, match) { | |
| 2037 | + const lexeme = match && match[0]; | |
| 2038 | + | |
| 2039 | + // add non-matched text to the current mode buffer | |
| 2040 | + modeBuffer += textBeforeMatch; | |
| 2041 | + | |
| 2042 | + if (lexeme == null) { | |
| 2043 | + processBuffer(); | |
| 2044 | + return 0; | |
| 2045 | + } | |
| 2046 | + | |
| 2047 | + // we've found a 0 width match and we're stuck, so we need to advance | |
| 2048 | + // this happens when we have badly behaved rules that have optional matchers to the degree that | |
| 2049 | + // sometimes they can end up matching nothing at all | |
| 2050 | + // Ref: https://github.com/highlightjs/highlight.js/issues/2140 | |
| 2051 | + if (lastMatch.type === "begin" && match.type === "end" && lastMatch.index === match.index && lexeme === "") { | |
| 2052 | + // spit the "skipped" character that our regex choked on back into the output sequence | |
| 2053 | + modeBuffer += codeToHighlight.slice(match.index, match.index + 1); | |
| 2054 | + if (!SAFE_MODE) { | |
| 2055 | + /** @type {AnnotatedError} */ | |
| 2056 | + const err = new Error(`0 width match regex (${languageName})`); | |
| 2057 | + err.languageName = languageName; | |
| 2058 | + err.badRule = lastMatch.rule; | |
| 2059 | + throw err; | |
| 2060 | + } | |
| 2061 | + return 1; | |
| 2062 | + } | |
| 2063 | + lastMatch = match; | |
| 2064 | + | |
| 2065 | + if (match.type === "begin") { | |
| 2066 | + return doBeginMatch(match); | |
| 2067 | + } else if (match.type === "illegal" && !ignoreIllegals) { | |
| 2068 | + // illegal match, we do not continue processing | |
| 2069 | + /** @type {AnnotatedError} */ | |
| 2070 | + const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.scope || '<unnamed>') + '"'); | |
| 2071 | + err.mode = top; | |
| 2072 | + throw err; | |
| 2073 | + } else if (match.type === "end") { | |
| 2074 | + const processed = doEndMatch(match); | |
| 2075 | + if (processed !== NO_MATCH) { | |
| 2076 | + return processed; | |
| 2077 | + } | |
| 2078 | + } | |
| 2079 | + | |
| 2080 | + // edge case for when illegal matches $ (end of line) which is technically | |
| 2081 | + // a 0 width match but not a begin/end match so it's not caught by the | |
| 2082 | + // first handler (when ignoreIllegals is true) | |
| 2083 | + if (match.type === "illegal" && lexeme === "") { | |
| 2084 | + // advance so we aren't stuck in an infinite loop | |
| 2085 | + modeBuffer += "\n"; | |
| 2086 | + return 1; | |
| 2087 | + } | |
| 2088 | + | |
| 2089 | + // infinite loops are BAD, this is a last ditch catch all. if we have a | |
| 2090 | + // decent number of iterations yet our index (cursor position in our | |
| 2091 | + // parsing) still 3x behind our index then something is very wrong | |
| 2092 | + // so we bail | |
| 2093 | + if (iterations > 100000 && iterations > match.index * 3) { | |
| 2094 | + const err = new Error('potential infinite loop, way more iterations than matches'); | |
| 2095 | + throw err; | |
| 2096 | + } | |
| 2097 | + | |
| 2098 | + /* | |
| 2099 | + Why might be find ourselves here? An potential end match that was | |
| 2100 | + triggered but could not be completed. IE, `doEndMatch` returned NO_MATCH. | |
| 2101 | + (this could be because a callback requests the match be ignored, etc) | |
| 2102 | + | |
| 2103 | + This causes no real harm other than stopping a few times too many. | |
| 2104 | + */ | |
| 2105 | + | |
| 2106 | + modeBuffer += lexeme; | |
| 2107 | + return lexeme.length; | |
| 2108 | + } | |
| 2109 | + | |
| 2110 | + const language = getLanguage(languageName); | |
| 2111 | + if (!language) { | |
| 2112 | + error(LANGUAGE_NOT_FOUND.replace("{}", languageName)); | |
| 2113 | + throw new Error('Unknown language: "' + languageName + '"'); | |
| 2114 | + } | |
| 2115 | + | |
| 2116 | + const md = compileLanguage(language); | |
| 2117 | + let result = ''; | |
| 2118 | + /** @type {CompiledMode} */ | |
| 2119 | + let top = continuation || md; | |
| 2120 | + /** @type Record<string,CompiledMode> */ | |
| 2121 | + const continuations = {}; // keep continuations for sub-languages | |
| 2122 | + const emitter = new options.__emitter(options); | |
| 2123 | + processContinuations(); | |
| 2124 | + let modeBuffer = ''; | |
| 2125 | + let relevance = 0; | |
| 2126 | + let index = 0; | |
| 2127 | + let iterations = 0; | |
| 2128 | + let resumeScanAtSamePosition = false; | |
| 2129 | + | |
| 2130 | + try { | |
| 2131 | + if (!language.__emitTokens) { | |
| 2132 | + top.matcher.considerAll(); | |
| 2133 | + | |
| 2134 | + for (;;) { | |
| 2135 | + iterations++; | |
| 2136 | + if (resumeScanAtSamePosition) { | |
| 2137 | + // only regexes not matched previously will now be | |
| 2138 | + // considered for a potential match | |
| 2139 | + resumeScanAtSamePosition = false; | |
| 2140 | + } else { | |
| 2141 | + top.matcher.considerAll(); | |
| 2142 | + } | |
| 2143 | + top.matcher.lastIndex = index; | |
| 2144 | + | |
| 2145 | + const match = top.matcher.exec(codeToHighlight); | |
| 2146 | + // console.log("match", match[0], match.rule && match.rule.begin) | |
| 2147 | + | |
| 2148 | + if (!match) break; | |
| 2149 | + | |
| 2150 | + const beforeMatch = codeToHighlight.substring(index, match.index); | |
| 2151 | + const processedCount = processLexeme(beforeMatch, match); | |
| 2152 | + index = match.index + processedCount; | |
| 2153 | + } | |
| 2154 | + processLexeme(codeToHighlight.substring(index)); | |
| 2155 | + } else { | |
| 2156 | + language.__emitTokens(codeToHighlight, emitter); | |
| 2157 | + } | |
| 2158 | + | |
| 2159 | + emitter.finalize(); | |
| 2160 | + result = emitter.toHTML(); | |
| 2161 | + | |
| 2162 | + return { | |
| 2163 | + language: languageName, | |
| 2164 | + value: result, | |
| 2165 | + relevance, | |
| 2166 | + illegal: false, | |
| 2167 | + _emitter: emitter, | |
| 2168 | + _top: top | |
| 2169 | + }; | |
| 2170 | + } catch (err) { | |
| 2171 | + if (err.message && err.message.includes('Illegal')) { | |
| 2172 | + return { | |
| 2173 | + language: languageName, | |
| 2174 | + value: escape(codeToHighlight), | |
| 2175 | + illegal: true, | |
| 2176 | + relevance: 0, | |
| 2177 | + _illegalBy: { | |
| 2178 | + message: err.message, | |
| 2179 | + index, | |
| 2180 | + context: codeToHighlight.slice(index - 100, index + 100), | |
| 2181 | + mode: err.mode, | |
| 2182 | + resultSoFar: result | |
| 2183 | + }, | |
| 2184 | + _emitter: emitter | |
| 2185 | + }; | |
| 2186 | + } else if (SAFE_MODE) { | |
| 2187 | + return { | |
| 2188 | + language: languageName, | |
| 2189 | + value: escape(codeToHighlight), | |
| 2190 | + illegal: false, | |
| 2191 | + relevance: 0, | |
| 2192 | + errorRaised: err, | |
| 2193 | + _emitter: emitter, | |
| 2194 | + _top: top | |
| 2195 | + }; | |
| 2196 | + } else { | |
| 2197 | + throw err; | |
| 2198 | + } | |
| 2199 | + } | |
| 2200 | + } | |
| 2201 | + | |
| 2202 | + /** | |
| 2203 | + * returns a valid highlight result, without actually doing any actual work, | |
| 2204 | + * auto highlight starts with this and it's possible for small snippets that | |
| 2205 | + * auto-detection may not find a better match | |
| 2206 | + * @param {string} code | |
| 2207 | + * @returns {HighlightResult} | |
| 2208 | + */ | |
| 2209 | + function justTextHighlightResult(code) { | |
| 2210 | + const result = { | |
| 2211 | + value: escape(code), | |
| 2212 | + illegal: false, | |
| 2213 | + relevance: 0, | |
| 2214 | + _top: PLAINTEXT_LANGUAGE, | |
| 2215 | + _emitter: new options.__emitter(options) | |
| 2216 | + }; | |
| 2217 | + result._emitter.addText(code); | |
| 2218 | + return result; | |
| 2219 | + } | |
| 2220 | + | |
| 2221 | + /** | |
| 2222 | + Highlighting with language detection. Accepts a string with the code to | |
| 2223 | + highlight. Returns an object with the following properties: | |
| 2224 | + | |
| 2225 | + - language (detected language) | |
| 2226 | + - relevance (int) | |
| 2227 | + - value (an HTML string with highlighting markup) | |
| 2228 | + - secondBest (object with the same structure for second-best heuristically | |
| 2229 | + detected language, may be absent) | |
| 2230 | + | |
| 2231 | + @param {string} code | |
| 2232 | + @param {Array<string>} [languageSubset] | |
| 2233 | + @returns {AutoHighlightResult} | |
| 2234 | + */ | |
| 2235 | + function highlightAuto(code, languageSubset) { | |
| 2236 | + languageSubset = languageSubset || options.languages || Object.keys(languages); | |
| 2237 | + const plaintext = justTextHighlightResult(code); | |
| 2238 | + | |
| 2239 | + const results = languageSubset.filter(getLanguage).filter(autoDetection).map(name => | |
| 2240 | + _highlight(name, code, false) | |
| 2241 | + ); | |
| 2242 | + results.unshift(plaintext); // plaintext is always an option | |
| 2243 | + | |
| 2244 | + const sorted = results.sort((a, b) => { | |
| 2245 | + // sort base on relevance | |
| 2246 | + if (a.relevance !== b.relevance) return b.relevance - a.relevance; | |
| 2247 | + | |
| 2248 | + // always award the tie to the base language | |
| 2249 | + // ie if C++ and Arduino are tied, it's more likely to be C++ | |
| 2250 | + if (a.language && b.language) { | |
| 2251 | + if (getLanguage(a.language).supersetOf === b.language) { | |
| 2252 | + return 1; | |
| 2253 | + } else if (getLanguage(b.language).supersetOf === a.language) { | |
| 2254 | + return -1; | |
| 2255 | + } | |
| 2256 | + } | |
| 2257 | + | |
| 2258 | + // otherwise say they are equal, which has the effect of sorting on | |
| 2259 | + // relevance while preserving the original ordering - which is how ties | |
| 2260 | + // have historically been settled, ie the language that comes first always | |
| 2261 | + // wins in the case of a tie | |
| 2262 | + return 0; | |
| 2263 | + }); | |
| 2264 | + | |
| 2265 | + const [best, secondBest] = sorted; | |
| 2266 | + | |
| 2267 | + /** @type {AutoHighlightResult} */ | |
| 2268 | + const result = best; | |
| 2269 | + result.secondBest = secondBest; | |
| 2270 | + | |
| 2271 | + return result; | |
| 2272 | + } | |
| 2273 | + | |
| 2274 | + /** | |
| 2275 | + * Builds new class name for block given the language name | |
| 2276 | + * | |
| 2277 | + * @param {HTMLElement} element | |
| 2278 | + * @param {string} [currentLang] | |
| 2279 | + * @param {string} [resultLang] | |
| 2280 | + */ | |
| 2281 | + function updateClassName(element, currentLang, resultLang) { | |
| 2282 | + const language = (currentLang && aliases[currentLang]) || resultLang; | |
| 2283 | + | |
| 2284 | + element.classList.add("hljs"); | |
| 2285 | + element.classList.add(`language-${language}`); | |
| 2286 | + } | |
| 2287 | + | |
| 2288 | + /** | |
| 2289 | + * Applies highlighting to a DOM node containing code. | |
| 2290 | + * | |
| 2291 | + * @param {HighlightedHTMLElement} element - the HTML element to highlight | |
| 2292 | + */ | |
| 2293 | + function highlightElement(element) { | |
| 2294 | + /** @type HTMLElement */ | |
| 2295 | + let node = null; | |
| 2296 | + const language = blockLanguage(element); | |
| 2297 | + | |
| 2298 | + if (shouldNotHighlight(language)) return; | |
| 2299 | + | |
| 2300 | + fire("before:highlightElement", | |
| 2301 | + { el: element, language }); | |
| 2302 | + | |
| 2303 | + if (element.dataset.highlighted) { | |
| 2304 | + console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.", element); | |
| 2305 | + return; | |
| 2306 | + } | |
| 2307 | + | |
| 2308 | + // we should be all text, no child nodes (unescaped HTML) - this is possibly | |
| 2309 | + // an HTML injection attack - it's likely too late if this is already in | |
| 2310 | + // production (the code has likely already done its damage by the time | |
| 2311 | + // we're seeing it)... but we yell loudly about this so that hopefully it's | |
| 2312 | + // more likely to be caught in development before making it to production | |
| 2313 | + if (element.children.length > 0) { | |
| 2314 | + if (!options.ignoreUnescapedHTML) { | |
| 2315 | + console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."); | |
| 2316 | + console.warn("https://github.com/highlightjs/highlight.js/wiki/security"); | |
| 2317 | + console.warn("The element with unescaped HTML:"); | |
| 2318 | + console.warn(element); | |
| 2319 | + } | |
| 2320 | + if (options.throwUnescapedHTML) { | |
| 2321 | + const err = new HTMLInjectionError( | |
| 2322 | + "One of your code blocks includes unescaped HTML.", | |
| 2323 | + element.innerHTML | |
| 2324 | + ); | |
| 2325 | + throw err; | |
| 2326 | + } | |
| 2327 | + } | |
| 2328 | + | |
| 2329 | + node = element; | |
| 2330 | + const text = node.textContent; | |
| 2331 | + const result = language ? highlight(text, { language, ignoreIllegals: true }) : highlightAuto(text); | |
| 2332 | + | |
| 2333 | + element.innerHTML = result.value; | |
| 2334 | + element.dataset.highlighted = "yes"; | |
| 2335 | + updateClassName(element, language, result.language); | |
| 2336 | + element.result = { | |
| 2337 | + language: result.language, | |
| 2338 | + // TODO: remove with version 11.0 | |
| 2339 | + re: result.relevance, | |
| 2340 | + relevance: result.relevance | |
| 2341 | + }; | |
| 2342 | + if (result.secondBest) { | |
| 2343 | + element.secondBest = { | |
| 2344 | + language: result.secondBest.language, | |
| 2345 | + relevance: result.secondBest.relevance | |
| 2346 | + }; | |
| 2347 | + } | |
| 2348 | + | |
| 2349 | + fire("after:highlightElement", { el: element, result, text }); | |
| 2350 | + } | |
| 2351 | + | |
| 2352 | + /** | |
| 2353 | + * Updates highlight.js global options with the passed options | |
| 2354 | + * | |
| 2355 | + * @param {Partial<HLJSOptions>} userOptions | |
| 2356 | + */ | |
| 2357 | + function configure(userOptions) { | |
| 2358 | + options = inherit(options, userOptions); | |
| 2359 | + } | |
| 2360 | + | |
| 2361 | + // TODO: remove v12, deprecated | |
| 2362 | + const initHighlighting = () => { | |
| 2363 | + highlightAll(); | |
| 2364 | + deprecated("10.6.0", "initHighlighting() deprecated. Use highlightAll() now."); | |
| 2365 | + }; | |
| 2366 | + | |
| 2367 | + // TODO: remove v12, deprecated | |
| 2368 | + function initHighlightingOnLoad() { | |
| 2369 | + highlightAll(); | |
| 2370 | + deprecated("10.6.0", "initHighlightingOnLoad() deprecated. Use highlightAll() now."); | |
| 2371 | + } | |
| 2372 | + | |
| 2373 | + let wantsHighlight = false; | |
| 2374 | + | |
| 2375 | + /** | |
| 2376 | + * auto-highlights all pre>code elements on the page | |
| 2377 | + */ | |
| 2378 | + function highlightAll() { | |
| 2379 | + function boot() { | |
| 2380 | + // if a highlight was requested before DOM was loaded, do now | |
| 2381 | + highlightAll(); | |
| 2382 | + } | |
| 2383 | + | |
| 2384 | + // if we are called too early in the loading process | |
| 2385 | + if (document.readyState === "loading") { | |
| 2386 | + // make sure the event listener is only added once | |
| 2387 | + if (!wantsHighlight) { | |
| 2388 | + window.addEventListener('DOMContentLoaded', boot, false); | |
| 2389 | + } | |
| 2390 | + wantsHighlight = true; | |
| 2391 | + return; | |
| 2392 | + } | |
| 2393 | + | |
| 2394 | + const blocks = document.querySelectorAll(options.cssSelector); | |
| 2395 | + blocks.forEach(highlightElement); | |
| 2396 | + } | |
| 2397 | + | |
| 2398 | + /** | |
| 2399 | + * Register a language grammar module | |
| 2400 | + * | |
| 2401 | + * @param {string} languageName | |
| 2402 | + * @param {LanguageFn} languageDefinition | |
| 2403 | + */ | |
| 2404 | + function registerLanguage(languageName, languageDefinition) { | |
| 2405 | + let lang = null; | |
| 2406 | + try { | |
| 2407 | + lang = languageDefinition(hljs); | |
| 2408 | + } catch (error$1) { | |
| 2409 | + error("Language definition for '{}' could not be registered.".replace("{}", languageName)); | |
| 2410 | + // hard or soft error | |
| 2411 | + if (!SAFE_MODE) { throw error$1; } else { error(error$1); } | |
| 2412 | + // languages that have serious errors are replaced with essentially a | |
| 2413 | + // "plaintext" stand-in so that the code blocks will still get normal | |
| 2414 | + // css classes applied to them - and one bad language won't break the | |
| 2415 | + // entire highlighter | |
| 2416 | + lang = PLAINTEXT_LANGUAGE; | |
| 2417 | + } | |
| 2418 | + // give it a temporary name if it doesn't have one in the meta-data | |
| 2419 | + if (!lang.name) lang.name = languageName; | |
| 2420 | + languages[languageName] = lang; | |
| 2421 | + lang.rawDefinition = languageDefinition.bind(null, hljs); | |
| 2422 | + | |
| 2423 | + if (lang.aliases) { | |
| 2424 | + registerAliases(lang.aliases, { languageName }); | |
| 2425 | + } | |
| 2426 | + } | |
| 2427 | + | |
| 2428 | + /** | |
| 2429 | + * Remove a language grammar module | |
| 2430 | + * | |
| 2431 | + * @param {string} languageName | |
| 2432 | + */ | |
| 2433 | + function unregisterLanguage(languageName) { | |
| 2434 | + delete languages[languageName]; | |
| 2435 | + for (const alias of Object.keys(aliases)) { | |
| 2436 | + if (aliases[alias] === languageName) { | |
| 2437 | + delete aliases[alias]; | |
| 2438 | + } | |
| 2439 | + } | |
| 2440 | + } | |
| 2441 | + | |
| 2442 | + /** | |
| 2443 | + * @returns {string[]} List of language internal names | |
| 2444 | + */ | |
| 2445 | + function listLanguages() { | |
| 2446 | + return Object.keys(languages); | |
| 2447 | + } | |
| 2448 | + | |
| 2449 | + /** | |
| 2450 | + * @param {string} name - name of the language to retrieve | |
| 2451 | + * @returns {Language | undefined} | |
| 2452 | + */ | |
| 2453 | + function getLanguage(name) { | |
| 2454 | + name = (name || '').toLowerCase(); | |
| 2455 | + return languages[name] || languages[aliases[name]]; | |
| 2456 | + } | |
| 2457 | + | |
| 2458 | + /** | |
| 2459 | + * | |
| 2460 | + * @param {string|string[]} aliasList - single alias or list of aliases | |
| 2461 | + * @param {{languageName: string}} opts | |
| 2462 | + */ | |
| 2463 | + function registerAliases(aliasList, { languageName }) { | |
| 2464 | + if (typeof aliasList === 'string') { | |
| 2465 | + aliasList = [aliasList]; | |
| 2466 | + } | |
| 2467 | + aliasList.forEach(alias => { aliases[alias.toLowerCase()] = languageName; }); | |
| 2468 | + } | |
| 2469 | + | |
| 2470 | + /** | |
| 2471 | + * Determines if a given language has auto-detection enabled | |
| 2472 | + * @param {string} name - name of the language | |
| 2473 | + */ | |
| 2474 | + function autoDetection(name) { | |
| 2475 | + const lang = getLanguage(name); | |
| 2476 | + return lang && !lang.disableAutodetect; | |
| 2477 | + } | |
| 2478 | + | |
| 2479 | + /** | |
| 2480 | + * Upgrades the old highlightBlock plugins to the new | |
| 2481 | + * highlightElement API | |
| 2482 | + * @param {HLJSPlugin} plugin | |
| 2483 | + */ | |
| 2484 | + function upgradePluginAPI(plugin) { | |
| 2485 | + // TODO: remove with v12 | |
| 2486 | + if (plugin["before:highlightBlock"] && !plugin["before:highlightElement"]) { | |
| 2487 | + plugin["before:highlightElement"] = (data) => { | |
| 2488 | + plugin["before:highlightBlock"]( | |
| 2489 | + Object.assign({ block: data.el }, data) | |
| 2490 | + ); | |
| 2491 | + }; | |
| 2492 | + } | |
| 2493 | + if (plugin["after:highlightBlock"] && !plugin["after:highlightElement"]) { | |
| 2494 | + plugin["after:highlightElement"] = (data) => { | |
| 2495 | + plugin["after:highlightBlock"]( | |
| 2496 | + Object.assign({ block: data.el }, data) | |
| 2497 | + ); | |
| 2498 | + }; | |
| 2499 | + } | |
| 2500 | + } | |
| 2501 | + | |
| 2502 | + /** | |
| 2503 | + * @param {HLJSPlugin} plugin | |
| 2504 | + */ | |
| 2505 | + function addPlugin(plugin) { | |
| 2506 | + upgradePluginAPI(plugin); | |
| 2507 | + plugins.push(plugin); | |
| 2508 | + } | |
| 2509 | + | |
| 2510 | + /** | |
| 2511 | + * @param {HLJSPlugin} plugin | |
| 2512 | + */ | |
| 2513 | + function removePlugin(plugin) { | |
| 2514 | + const index = plugins.indexOf(plugin); | |
| 2515 | + if (index !== -1) { | |
| 2516 | + plugins.splice(index, 1); | |
| 2517 | + } | |
| 2518 | + } | |
| 2519 | + | |
| 2520 | + /** | |
| 2521 | + * | |
| 2522 | + * @param {PluginEvent} event | |
| 2523 | + * @param {any} args | |
| 2524 | + */ | |
| 2525 | + function fire(event, args) { | |
| 2526 | + const cb = event; | |
| 2527 | + plugins.forEach(function(plugin) { | |
| 2528 | + if (plugin[cb]) { | |
| 2529 | + plugin[cb](args); | |
| 2530 | + } | |
| 2531 | + }); | |
| 2532 | + } | |
| 2533 | + | |
| 2534 | + /** | |
| 2535 | + * DEPRECATED | |
| 2536 | + * @param {HighlightedHTMLElement} el | |
| 2537 | + */ | |
| 2538 | + function deprecateHighlightBlock(el) { | |
| 2539 | + deprecated("10.7.0", "highlightBlock will be removed entirely in v12.0"); | |
| 2540 | + deprecated("10.7.0", "Please use highlightElement now."); | |
| 2541 | + | |
| 2542 | + return highlightElement(el); | |
| 2543 | + } | |
| 2544 | + | |
| 2545 | + /* Interface definition */ | |
| 2546 | + Object.assign(hljs, { | |
| 2547 | + highlight, | |
| 2548 | + highlightAuto, | |
| 2549 | + highlightAll, | |
| 2550 | + highlightElement, | |
| 2551 | + // TODO: Remove with v12 API | |
| 2552 | + highlightBlock: deprecateHighlightBlock, | |
| 2553 | + configure, | |
| 2554 | + initHighlighting, | |
| 2555 | + initHighlightingOnLoad, | |
| 2556 | + registerLanguage, | |
| 2557 | + unregisterLanguage, | |
| 2558 | + listLanguages, | |
| 2559 | + getLanguage, | |
| 2560 | + registerAliases, | |
| 2561 | + autoDetection, | |
| 2562 | + inherit, | |
| 2563 | + addPlugin, | |
| 2564 | + removePlugin | |
| 2565 | + }); | |
| 2566 | + | |
| 2567 | + hljs.debugMode = function() { SAFE_MODE = false; }; | |
| 2568 | + hljs.safeMode = function() { SAFE_MODE = true; }; | |
| 2569 | + hljs.versionString = version; | |
| 2570 | + | |
| 2571 | + hljs.regex = { | |
| 2572 | + concat: concat, | |
| 2573 | + lookahead: lookahead, | |
| 2574 | + either: either, | |
| 2575 | + optional: optional, | |
| 2576 | + anyNumberOfTimes: anyNumberOfTimes | |
| 2577 | + }; | |
| 2578 | + | |
| 2579 | + for (const key in MODES) { | |
| 2580 | + // @ts-ignore | |
| 2581 | + if (typeof MODES[key] === "object") { | |
| 2582 | + // @ts-ignore | |
| 2583 | + deepFreeze(MODES[key]); | |
| 2584 | + } | |
| 2585 | + } | |
| 2586 | + | |
| 2587 | + // merge all the modes/regexes into our main object | |
| 2588 | + Object.assign(hljs, MODES); | |
| 2589 | + | |
| 2590 | + return hljs; | |
| 2591 | +}; | |
| 2592 | + | |
| 2593 | +// Other names for the variable may break build script | |
| 2594 | +const highlight = HLJS({}); | |
| 2595 | + | |
| 2596 | +// returns a new instance of the highlighter to be used for extensions | |
| 2597 | +// check https://github.com/wooorm/lowlight/issues/47 | |
| 2598 | +highlight.newInstance = () => HLJS({}); | |
| 2599 | + | |
| 2600 | +export { highlight as default }; |
+++ src/main/webapp/publish/js/highlight/es/core.min.js
... | ... | @@ -0,0 +1,306 @@ |
| 1 | +/*! | |
| 2 | + Highlight.js v11.11.1 (git: 08cb242e7d) | |
| 3 | + (c) 2006-2025 Josh Goebel <hello@joshgoebel.com> and other contributors | |
| 4 | + License: BSD-3-Clause | |
| 5 | + */ | |
| 6 | +function e(t){return t instanceof Map?t.clear=t.delete=t.set=()=>{ | |
| 7 | +throw Error("map is read-only")}:t instanceof Set&&(t.add=t.clear=t.delete=()=>{ | |
| 8 | +throw Error("set is read-only") | |
| 9 | +}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach((n=>{ | |
| 10 | +const i=t[n],s=typeof i;"object"!==s&&"function"!==s||Object.isFrozen(i)||e(i) | |
| 11 | +})),t}class t{constructor(e){ | |
| 12 | +void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1} | |
| 13 | +ignoreMatch(){this.isMatchIgnored=!0}}function n(e){ | |
| 14 | +return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'") | |
| 15 | +}function i(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t] | |
| 16 | +;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const s=e=>!!e.scope | |
| 17 | +;class r{constructor(e,t){ | |
| 18 | +this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){ | |
| 19 | +this.buffer+=n(e)}openNode(e){if(!s(e))return;const t=((e,{prefix:t})=>{ | |
| 20 | +if(e.startsWith("language:"))return e.replace("language:","language-") | |
| 21 | +;if(e.includes(".")){const n=e.split(".") | |
| 22 | +;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ") | |
| 23 | +}return`${t}${e}`})(e.scope,{prefix:this.classPrefix});this.span(t)} | |
| 24 | +closeNode(e){s(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){ | |
| 25 | +this.buffer+=`<span class="${e}">`}}const o=(e={})=>{const t={children:[]} | |
| 26 | +;return Object.assign(t,e),t};class a{constructor(){ | |
| 27 | +this.rootNode=o(),this.stack=[this.rootNode]}get top(){ | |
| 28 | +return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ | |
| 29 | +this.top.children.push(e)}openNode(e){const t=o({scope:e}) | |
| 30 | +;this.add(t),this.stack.push(t)}closeNode(){ | |
| 31 | +if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ | |
| 32 | +for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} | |
| 33 | +walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){ | |
| 34 | +return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t), | |
| 35 | +t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){ | |
| 36 | +"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ | |
| 37 | +a._collapse(e)})))}}class c extends a{constructor(e){super(),this.options=e} | |
| 38 | +addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){ | |
| 39 | +this.closeNode()}__addSublanguage(e,t){const n=e.root | |
| 40 | +;t&&(n.scope="language:"+t),this.add(n)}toHTML(){ | |
| 41 | +return new r(this,this.options).value()}finalize(){ | |
| 42 | +return this.closeAllNodes(),!0}}function l(e){ | |
| 43 | +return e?"string"==typeof e?e:e.source:null}function g(e){return h("(?=",e,")")} | |
| 44 | +function u(e){return h("(?:",e,")*")}function d(e){return h("(?:",e,")?")} | |
| 45 | +function h(...e){return e.map((e=>l(e))).join("")}function f(...e){const t=(e=>{ | |
| 46 | +const t=e[e.length-1] | |
| 47 | +;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{} | |
| 48 | +})(e);return"("+(t.capture?"":"?:")+e.map((e=>l(e))).join("|")+")"} | |
| 49 | +function p(e){return RegExp(e.toString()+"|").exec("").length-1} | |
| 50 | +const b=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./ | |
| 51 | +;function m(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n | |
| 52 | +;let i=l(e),s="";for(;i.length>0;){const e=b.exec(i);if(!e){s+=i;break} | |
| 53 | +s+=i.substring(0,e.index), | |
| 54 | +i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?s+="\\"+(Number(e[1])+t):(s+=e[0], | |
| 55 | +"("===e[0]&&n++)}return s})).map((e=>`(${e})`)).join(t)} | |
| 56 | +const E="[a-zA-Z]\\w*",x="[a-zA-Z_]\\w*",_="\\b\\d+(\\.\\d+)?",y="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",O={ | |
| 57 | +begin:"\\\\[\\s\\S]",relevance:0},k={scope:"string",begin:"'",end:"'", | |
| 58 | +illegal:"\\n",contains:[O]},v={scope:"string",begin:'"',end:'"',illegal:"\\n", | |
| 59 | +contains:[O]},N=(e,t,n={})=>{const s=i({scope:"comment",begin:e,end:t, | |
| 60 | +contains:[]},n);s.contains.push({scope:"doctag", | |
| 61 | +begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)", | |
| 62 | +end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0}) | |
| 63 | +;const r=f("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/) | |
| 64 | +;return s.contains.push({begin:h(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),s | |
| 65 | +},S=N("//","$"),M=N("/\\*","\\*/"),R=N("#","$");var A=Object.freeze({ | |
| 66 | +__proto__:null,APOS_STRING_MODE:k,BACKSLASH_ESCAPE:O,BINARY_NUMBER_MODE:{ | |
| 67 | +scope:"number",begin:w,relevance:0},BINARY_NUMBER_RE:w,COMMENT:N, | |
| 68 | +C_BLOCK_COMMENT_MODE:M,C_LINE_COMMENT_MODE:S,C_NUMBER_MODE:{scope:"number", | |
| 69 | +begin:y,relevance:0},C_NUMBER_RE:y,END_SAME_AS_BEGIN:e=>Object.assign(e,{ | |
| 70 | +"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{ | |
| 71 | +t.data._beginMatch!==e[1]&&t.ignoreMatch()}}),HASH_COMMENT_MODE:R,IDENT_RE:E, | |
| 72 | +MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+x,relevance:0}, | |
| 73 | +NUMBER_MODE:{scope:"number",begin:_,relevance:0},NUMBER_RE:_, | |
| 74 | +PHRASAL_WORDS_MODE:{ | |
| 75 | +begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ | |
| 76 | +},QUOTE_STRING_MODE:v,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/, | |
| 77 | +end:/\/[gimuy]*/,contains:[O,{begin:/\[/,end:/\]/,relevance:0,contains:[O]}]}, | |
| 78 | +RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", | |
| 79 | +SHEBANG:(e={})=>{const t=/^#![ ]*\// | |
| 80 | +;return e.binary&&(e.begin=h(t,/.*\b/,e.binary,/\b.*/)),i({scope:"meta",begin:t, | |
| 81 | +end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)}, | |
| 82 | +TITLE_MODE:{scope:"title",begin:E,relevance:0},UNDERSCORE_IDENT_RE:x, | |
| 83 | +UNDERSCORE_TITLE_MODE:{scope:"title",begin:x,relevance:0}});function j(e,t){ | |
| 84 | +"."===e.input[e.index-1]&&t.ignoreMatch()}function I(e,t){ | |
| 85 | +void 0!==e.className&&(e.scope=e.className,delete e.className)}function T(e,t){ | |
| 86 | +t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)", | |
| 87 | +e.__beforeBegin=j,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords, | |
| 88 | +void 0===e.relevance&&(e.relevance=0))}function L(e,t){ | |
| 89 | +Array.isArray(e.illegal)&&(e.illegal=f(...e.illegal))}function B(e,t){ | |
| 90 | +if(e.match){ | |
| 91 | +if(e.begin||e.end)throw Error("begin & end are not supported with match") | |
| 92 | +;e.begin=e.match,delete e.match}}function P(e,t){ | |
| 93 | +void 0===e.relevance&&(e.relevance=1)}const D=(e,t)=>{if(!e.beforeMatch)return | |
| 94 | +;if(e.starts)throw Error("beforeMatch cannot be used with starts") | |
| 95 | +;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t] | |
| 96 | +})),e.keywords=n.keywords,e.begin=h(n.beforeMatch,g(n.begin)),e.starts={ | |
| 97 | +relevance:0,contains:[Object.assign(n,{endsParent:!0})] | |
| 98 | +},e.relevance=0,delete n.beforeMatch | |
| 99 | +},H=["of","and","for","in","not","or","if","then","parent","list","value"] | |
| 100 | +;function C(e,t,n="keyword"){const i=Object.create(null) | |
| 101 | +;return"string"==typeof e?s(n,e.split(" ")):Array.isArray(e)?s(n,e):Object.keys(e).forEach((n=>{ | |
| 102 | +Object.assign(i,C(e[n],t,n))})),i;function s(e,n){ | |
| 103 | +t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|") | |
| 104 | +;i[n[0]]=[e,$(n[0],n[1])]}))}}function $(e,t){ | |
| 105 | +return t?Number(t):(e=>H.includes(e.toLowerCase()))(e)?0:1}const U={},z=e=>{ | |
| 106 | +console.error(e)},W=(e,...t)=>{console.log("WARN: "+e,...t)},X=(e,t)=>{ | |
| 107 | +U[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),U[`${e}/${t}`]=!0) | |
| 108 | +},G=Error();function K(e,t,{key:n}){let i=0;const s=e[n],r={},o={} | |
| 109 | +;for(let e=1;e<=t.length;e++)o[e+i]=s[e],r[e+i]=!0,i+=p(t[e-1]) | |
| 110 | +;e[n]=o,e[n]._emit=r,e[n]._multi=!0}function F(e){(e=>{ | |
| 111 | +e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope, | |
| 112 | +delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={ | |
| 113 | +_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope | |
| 114 | +}),(e=>{if(Array.isArray(e.begin)){ | |
| 115 | +if(e.skip||e.excludeBegin||e.returnBegin)throw z("skip, excludeBegin, returnBegin not compatible with beginScope: {}"), | |
| 116 | +G | |
| 117 | +;if("object"!=typeof e.beginScope||null===e.beginScope)throw z("beginScope must be object"), | |
| 118 | +G;K(e,e.begin,{key:"beginScope"}),e.begin=m(e.begin,{joinWith:""})}})(e),(e=>{ | |
| 119 | +if(Array.isArray(e.end)){ | |
| 120 | +if(e.skip||e.excludeEnd||e.returnEnd)throw z("skip, excludeEnd, returnEnd not compatible with endScope: {}"), | |
| 121 | +G | |
| 122 | +;if("object"!=typeof e.endScope||null===e.endScope)throw z("endScope must be object"), | |
| 123 | +G;K(e,e.end,{key:"endScope"}),e.end=m(e.end,{joinWith:""})}})(e)}function Z(e){ | |
| 124 | +function t(t,n){ | |
| 125 | +return RegExp(l(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(n?"g":"")) | |
| 126 | +}class n{constructor(){ | |
| 127 | +this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} | |
| 128 | +addRule(e,t){ | |
| 129 | +t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]), | |
| 130 | +this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) | |
| 131 | +;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(m(e,{joinWith:"|" | |
| 132 | +}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex | |
| 133 | +;const t=this.matcherRe.exec(e);if(!t)return null | |
| 134 | +;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n] | |
| 135 | +;return t.splice(0,n),Object.assign(t,i)}}class s{constructor(){ | |
| 136 | +this.rules=[],this.multiRegexes=[], | |
| 137 | +this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ | |
| 138 | +if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n | |
| 139 | +;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))), | |
| 140 | +t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){ | |
| 141 | +return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){ | |
| 142 | +this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){ | |
| 143 | +const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex | |
| 144 | +;let n=t.exec(e) | |
| 145 | +;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{ | |
| 146 | +const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)} | |
| 147 | +return n&&(this.regexIndex+=n.position+1, | |
| 148 | +this.regexIndex===this.count&&this.considerAll()),n}} | |
| 149 | +if(e.compilerExtensions||(e.compilerExtensions=[]), | |
| 150 | +e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") | |
| 151 | +;return e.classNameAliases=i(e.classNameAliases||{}),function n(r,o){const a=r | |
| 152 | +;if(r.isCompiled)return a | |
| 153 | +;[I,B,F,D].forEach((e=>e(r,o))),e.compilerExtensions.forEach((e=>e(r,o))), | |
| 154 | +r.__beforeBegin=null,[T,L,P].forEach((e=>e(r,o))),r.isCompiled=!0;let c=null | |
| 155 | +;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords), | |
| 156 | +c=r.keywords.$pattern, | |
| 157 | +delete r.keywords.$pattern),c=c||/\w+/,r.keywords&&(r.keywords=C(r.keywords,e.case_insensitive)), | |
| 158 | +a.keywordPatternRe=t(c,!0), | |
| 159 | +o&&(r.begin||(r.begin=/\B|\b/),a.beginRe=t(a.begin),r.end||r.endsWithParent||(r.end=/\B|\b/), | |
| 160 | +r.end&&(a.endRe=t(a.end)), | |
| 161 | +a.terminatorEnd=l(a.end)||"",r.endsWithParent&&o.terminatorEnd&&(a.terminatorEnd+=(r.end?"|":"")+o.terminatorEnd)), | |
| 162 | +r.illegal&&(a.illegalRe=t(r.illegal)), | |
| 163 | +r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>i(e,{ | |
| 164 | +variants:null},t)))),e.cachedVariants?e.cachedVariants:V(e)?i(e,{ | |
| 165 | +starts:e.starts?i(e.starts):null | |
| 166 | +}):Object.isFrozen(e)?i(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{n(e,a) | |
| 167 | +})),r.starts&&n(r.starts,o),a.matcher=(e=>{const t=new s | |
| 168 | +;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin" | |
| 169 | +}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end" | |
| 170 | +}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function V(e){ | |
| 171 | +return!!e&&(e.endsWithParent||V(e.starts))}class q extends Error{ | |
| 172 | +constructor(e,t){super(e),this.name="HTMLInjectionError",this.html=t}} | |
| 173 | +const J=n,Y=i,Q=Symbol("nomatch"),ee=n=>{ | |
| 174 | +const i=Object.create(null),s=Object.create(null),r=[];let o=!0 | |
| 175 | +;const a="Could not find the language '{}', did you forget to load/include a language module?",l={ | |
| 176 | +disableAutodetect:!0,name:"Plain text",contains:[]};let p={ | |
| 177 | +ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i, | |
| 178 | +languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", | |
| 179 | +cssSelector:"pre code",languages:null,__emitter:c};function b(e){ | |
| 180 | +return p.noHighlightRe.test(e)}function m(e,t,n){let i="",s="" | |
| 181 | +;"object"==typeof t?(i=e, | |
| 182 | +n=t.ignoreIllegals,s=t.language):(X("10.7.0","highlight(lang, code, ...args) has been deprecated."), | |
| 183 | +X("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"), | |
| 184 | +s=e,i=t),void 0===n&&(n=!0);const r={code:i,language:s};N("before:highlight",r) | |
| 185 | +;const o=r.result?r.result:E(r.language,r.code,n) | |
| 186 | +;return o.code=r.code,N("after:highlight",o),o}function E(e,n,s,r){ | |
| 187 | +const c=Object.create(null);function l(){if(!N.keywords)return void M.addText(R) | |
| 188 | +;let e=0;N.keywordPatternRe.lastIndex=0;let t=N.keywordPatternRe.exec(R),n="" | |
| 189 | +;for(;t;){n+=R.substring(e,t.index) | |
| 190 | +;const s=w.case_insensitive?t[0].toLowerCase():t[0],r=(i=s,N.keywords[i]);if(r){ | |
| 191 | +const[e,i]=r | |
| 192 | +;if(M.addText(n),n="",c[s]=(c[s]||0)+1,c[s]<=7&&(A+=i),e.startsWith("_"))n+=t[0];else{ | |
| 193 | +const n=w.classNameAliases[e]||e;u(t[0],n)}}else n+=t[0] | |
| 194 | +;e=N.keywordPatternRe.lastIndex,t=N.keywordPatternRe.exec(R)}var i | |
| 195 | +;n+=R.substring(e),M.addText(n)}function g(){null!=N.subLanguage?(()=>{ | |
| 196 | +if(""===R)return;let e=null;if("string"==typeof N.subLanguage){ | |
| 197 | +if(!i[N.subLanguage])return void M.addText(R) | |
| 198 | +;e=E(N.subLanguage,R,!0,S[N.subLanguage]),S[N.subLanguage]=e._top | |
| 199 | +}else e=x(R,N.subLanguage.length?N.subLanguage:null) | |
| 200 | +;N.relevance>0&&(A+=e.relevance),M.__addSublanguage(e._emitter,e.language) | |
| 201 | +})():l(),R=""}function u(e,t){ | |
| 202 | +""!==e&&(M.startScope(t),M.addText(e),M.endScope())}function d(e,t){let n=1 | |
| 203 | +;const i=t.length-1;for(;n<=i;){if(!e._emit[n]){n++;continue} | |
| 204 | +const i=w.classNameAliases[e[n]]||e[n],s=t[n];i?u(s,i):(R=s,l(),R=""),n++}} | |
| 205 | +function h(e,t){ | |
| 206 | +return e.scope&&"string"==typeof e.scope&&M.openNode(w.classNameAliases[e.scope]||e.scope), | |
| 207 | +e.beginScope&&(e.beginScope._wrap?(u(R,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap), | |
| 208 | +R=""):e.beginScope._multi&&(d(e.beginScope,t),R="")),N=Object.create(e,{parent:{ | |
| 209 | +value:N}}),N}function f(e,n,i){let s=((e,t)=>{const n=e&&e.exec(t) | |
| 210 | +;return n&&0===n.index})(e.endRe,i);if(s){if(e["on:end"]){const i=new t(e) | |
| 211 | +;e["on:end"](n,i),i.isMatchIgnored&&(s=!1)}if(s){ | |
| 212 | +for(;e.endsParent&&e.parent;)e=e.parent;return e}} | |
| 213 | +if(e.endsWithParent)return f(e.parent,n,i)}function b(e){ | |
| 214 | +return 0===N.matcher.regexIndex?(R+=e[0],1):(T=!0,0)}function m(e){ | |
| 215 | +const t=e[0],i=n.substring(e.index),s=f(N,e,i);if(!s)return Q;const r=N | |
| 216 | +;N.endScope&&N.endScope._wrap?(g(), | |
| 217 | +u(t,N.endScope._wrap)):N.endScope&&N.endScope._multi?(g(), | |
| 218 | +d(N.endScope,e)):r.skip?R+=t:(r.returnEnd||r.excludeEnd||(R+=t), | |
| 219 | +g(),r.excludeEnd&&(R=t));do{ | |
| 220 | +N.scope&&M.closeNode(),N.skip||N.subLanguage||(A+=N.relevance),N=N.parent | |
| 221 | +}while(N!==s.parent);return s.starts&&h(s.starts,e),r.returnEnd?0:t.length} | |
| 222 | +let _={};function y(i,r){const a=r&&r[0];if(R+=i,null==a)return g(),0 | |
| 223 | +;if("begin"===_.type&&"end"===r.type&&_.index===r.index&&""===a){ | |
| 224 | +if(R+=n.slice(r.index,r.index+1),!o){const t=Error(`0 width match regex (${e})`) | |
| 225 | +;throw t.languageName=e,t.badRule=_.rule,t}return 1} | |
| 226 | +if(_=r,"begin"===r.type)return(e=>{ | |
| 227 | +const n=e[0],i=e.rule,s=new t(i),r=[i.__beforeBegin,i["on:begin"]] | |
| 228 | +;for(const t of r)if(t&&(t(e,s),s.isMatchIgnored))return b(n) | |
| 229 | +;return i.skip?R+=n:(i.excludeBegin&&(R+=n), | |
| 230 | +g(),i.returnBegin||i.excludeBegin||(R=n)),h(i,e),i.returnBegin?0:n.length})(r) | |
| 231 | +;if("illegal"===r.type&&!s){ | |
| 232 | +const e=Error('Illegal lexeme "'+a+'" for mode "'+(N.scope||"<unnamed>")+'"') | |
| 233 | +;throw e.mode=N,e}if("end"===r.type){const e=m(r);if(e!==Q)return e} | |
| 234 | +if("illegal"===r.type&&""===a)return R+="\n",1 | |
| 235 | +;if(I>1e5&&I>3*r.index)throw Error("potential infinite loop, way more iterations than matches") | |
| 236 | +;return R+=a,a.length}const w=O(e) | |
| 237 | +;if(!w)throw z(a.replace("{}",e)),Error('Unknown language: "'+e+'"') | |
| 238 | +;const k=Z(w);let v="",N=r||k;const S={},M=new p.__emitter(p);(()=>{const e=[] | |
| 239 | +;for(let t=N;t!==w;t=t.parent)t.scope&&e.unshift(t.scope) | |
| 240 | +;e.forEach((e=>M.openNode(e)))})();let R="",A=0,j=0,I=0,T=!1;try{ | |
| 241 | +if(w.__emitTokens)w.__emitTokens(n,M);else{for(N.matcher.considerAll();;){ | |
| 242 | +I++,T?T=!1:N.matcher.considerAll(),N.matcher.lastIndex=j | |
| 243 | +;const e=N.matcher.exec(n);if(!e)break;const t=y(n.substring(j,e.index),e) | |
| 244 | +;j=e.index+t}y(n.substring(j))}return M.finalize(),v=M.toHTML(),{language:e, | |
| 245 | +value:v,relevance:A,illegal:!1,_emitter:M,_top:N}}catch(t){ | |
| 246 | +if(t.message&&t.message.includes("Illegal"))return{language:e,value:J(n), | |
| 247 | +illegal:!0,relevance:0,_illegalBy:{message:t.message,index:j, | |
| 248 | +context:n.slice(j-100,j+100),mode:t.mode,resultSoFar:v},_emitter:M};if(o)return{ | |
| 249 | +language:e,value:J(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:N} | |
| 250 | +;throw t}}function x(e,t){t=t||p.languages||Object.keys(i);const n=(e=>{ | |
| 251 | +const t={value:J(e),illegal:!1,relevance:0,_top:l,_emitter:new p.__emitter(p)} | |
| 252 | +;return t._emitter.addText(e),t})(e),s=t.filter(O).filter(v).map((t=>E(t,e,!1))) | |
| 253 | +;s.unshift(n);const r=s.sort(((e,t)=>{ | |
| 254 | +if(e.relevance!==t.relevance)return t.relevance-e.relevance | |
| 255 | +;if(e.language&&t.language){if(O(e.language).supersetOf===t.language)return 1 | |
| 256 | +;if(O(t.language).supersetOf===e.language)return-1}return 0})),[o,a]=r,c=o | |
| 257 | +;return c.secondBest=a,c}function _(e){let t=null;const n=(e=>{ | |
| 258 | +let t=e.className+" ";t+=e.parentNode?e.parentNode.className:"" | |
| 259 | +;const n=p.languageDetectRe.exec(t);if(n){const t=O(n[1]) | |
| 260 | +;return t||(W(a.replace("{}",n[1])), | |
| 261 | +W("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"} | |
| 262 | +return t.split(/\s+/).find((e=>b(e)||O(e)))})(e);if(b(n))return | |
| 263 | +;if(N("before:highlightElement",{el:e,language:n | |
| 264 | +}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e) | |
| 265 | +;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."), | |
| 266 | +console.warn("https://github.com/highlightjs/highlight.js/wiki/security"), | |
| 267 | +console.warn("The element with unescaped HTML:"), | |
| 268 | +console.warn(e)),p.throwUnescapedHTML))throw new q("One of your code blocks includes unescaped HTML.",e.innerHTML) | |
| 269 | +;t=e;const i=t.textContent,r=n?m(i,{language:n,ignoreIllegals:!0}):x(i) | |
| 270 | +;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,t,n)=>{const i=t&&s[t]||n | |
| 271 | +;e.classList.add("hljs"),e.classList.add("language-"+i) | |
| 272 | +})(e,n,r.language),e.result={language:r.language,re:r.relevance, | |
| 273 | +relevance:r.relevance},r.secondBest&&(e.secondBest={ | |
| 274 | +language:r.secondBest.language,relevance:r.secondBest.relevance | |
| 275 | +}),N("after:highlightElement",{el:e,result:r,text:i})}let y=!1;function w(){ | |
| 276 | +if("loading"===document.readyState)return y||window.addEventListener("DOMContentLoaded",(()=>{ | |
| 277 | +w()}),!1),void(y=!0);document.querySelectorAll(p.cssSelector).forEach(_)} | |
| 278 | +function O(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]} | |
| 279 | +function k(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{ | |
| 280 | +s[e.toLowerCase()]=t}))}function v(e){const t=O(e) | |
| 281 | +;return t&&!t.disableAutodetect}function N(e,t){const n=e;r.forEach((e=>{ | |
| 282 | +e[n]&&e[n](t)}))}Object.assign(n,{highlight:m,highlightAuto:x,highlightAll:w, | |
| 283 | +highlightElement:_, | |
| 284 | +highlightBlock:e=>(X("10.7.0","highlightBlock will be removed entirely in v12.0"), | |
| 285 | +X("10.7.0","Please use highlightElement now."),_(e)),configure:e=>{p=Y(p,e)}, | |
| 286 | +initHighlighting:()=>{ | |
| 287 | +w(),X("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")}, | |
| 288 | +initHighlightingOnLoad:()=>{ | |
| 289 | +w(),X("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.") | |
| 290 | +},registerLanguage:(e,t)=>{let s=null;try{s=t(n)}catch(t){ | |
| 291 | +if(z("Language definition for '{}' could not be registered.".replace("{}",e)), | |
| 292 | +!o)throw t;z(t),s=l} | |
| 293 | +s.name||(s.name=e),i[e]=s,s.rawDefinition=t.bind(null,n),s.aliases&&k(s.aliases,{ | |
| 294 | +languageName:e})},unregisterLanguage:e=>{delete i[e] | |
| 295 | +;for(const t of Object.keys(s))s[t]===e&&delete s[t]}, | |
| 296 | +listLanguages:()=>Object.keys(i),getLanguage:O,registerAliases:k, | |
| 297 | +autoDetection:v,inherit:Y,addPlugin:e=>{(e=>{ | |
| 298 | +e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{ | |
| 299 | +e["before:highlightBlock"](Object.assign({block:t.el},t)) | |
| 300 | +}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{ | |
| 301 | +e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),r.push(e)}, | |
| 302 | +removePlugin:e=>{const t=r.indexOf(e);-1!==t&&r.splice(t,1)}}),n.debugMode=()=>{ | |
| 303 | +o=!1},n.safeMode=()=>{o=!0},n.versionString="11.11.1",n.regex={concat:h, | |
| 304 | +lookahead:g,either:f,optional:d,anyNumberOfTimes:u} | |
| 305 | +;for(const t in A)"object"==typeof A[t]&&e(A[t]);return Object.assign(n,A),n | |
| 306 | +},te=ee({});te.newInstance=()=>ee({});export{te as default};(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/highlight.js
... | ... | @@ -0,0 +1,2600 @@ |
| 1 | +/*! | |
| 2 | + Highlight.js v11.11.1 (git: 08cb242e7d) | |
| 3 | + (c) 2006-2025 Josh Goebel <hello@joshgoebel.com> and other contributors | |
| 4 | + License: BSD-3-Clause | |
| 5 | + */ | |
| 6 | +/* eslint-disable no-multi-assign */ | |
| 7 | + | |
| 8 | +function deepFreeze(obj) { | |
| 9 | + if (obj instanceof Map) { | |
| 10 | + obj.clear = | |
| 11 | + obj.delete = | |
| 12 | + obj.set = | |
| 13 | + function () { | |
| 14 | + throw new Error('map is read-only'); | |
| 15 | + }; | |
| 16 | + } else if (obj instanceof Set) { | |
| 17 | + obj.add = | |
| 18 | + obj.clear = | |
| 19 | + obj.delete = | |
| 20 | + function () { | |
| 21 | + throw new Error('set is read-only'); | |
| 22 | + }; | |
| 23 | + } | |
| 24 | + | |
| 25 | + // Freeze self | |
| 26 | + Object.freeze(obj); | |
| 27 | + | |
| 28 | + Object.getOwnPropertyNames(obj).forEach((name) => { | |
| 29 | + const prop = obj[name]; | |
| 30 | + const type = typeof prop; | |
| 31 | + | |
| 32 | + // Freeze prop if it is an object or function and also not already frozen | |
| 33 | + if ((type === 'object' || type === 'function') && !Object.isFrozen(prop)) { | |
| 34 | + deepFreeze(prop); | |
| 35 | + } | |
| 36 | + }); | |
| 37 | + | |
| 38 | + return obj; | |
| 39 | +} | |
| 40 | + | |
| 41 | +/** @typedef {import('highlight.js').CallbackResponse} CallbackResponse */ | |
| 42 | +/** @typedef {import('highlight.js').CompiledMode} CompiledMode */ | |
| 43 | +/** @implements CallbackResponse */ | |
| 44 | + | |
| 45 | +class Response { | |
| 46 | + /** | |
| 47 | + * @param {CompiledMode} mode | |
| 48 | + */ | |
| 49 | + constructor(mode) { | |
| 50 | + // eslint-disable-next-line no-undefined | |
| 51 | + if (mode.data === undefined) mode.data = {}; | |
| 52 | + | |
| 53 | + this.data = mode.data; | |
| 54 | + this.isMatchIgnored = false; | |
| 55 | + } | |
| 56 | + | |
| 57 | + ignoreMatch() { | |
| 58 | + this.isMatchIgnored = true; | |
| 59 | + } | |
| 60 | +} | |
| 61 | + | |
| 62 | +/** | |
| 63 | + * @param {string} value | |
| 64 | + * @returns {string} | |
| 65 | + */ | |
| 66 | +function escapeHTML(value) { | |
| 67 | + return value | |
| 68 | + .replace(/&/g, '&') | |
| 69 | + .replace(/</g, '<') | |
| 70 | + .replace(/>/g, '>') | |
| 71 | + .replace(/"/g, '"') | |
| 72 | + .replace(/'/g, '''); | |
| 73 | +} | |
| 74 | + | |
| 75 | +/** | |
| 76 | + * performs a shallow merge of multiple objects into one | |
| 77 | + * | |
| 78 | + * @template T | |
| 79 | + * @param {T} original | |
| 80 | + * @param {Record<string,any>[]} objects | |
| 81 | + * @returns {T} a single new object | |
| 82 | + */ | |
| 83 | +function inherit$1(original, ...objects) { | |
| 84 | + /** @type Record<string,any> */ | |
| 85 | + const result = Object.create(null); | |
| 86 | + | |
| 87 | + for (const key in original) { | |
| 88 | + result[key] = original[key]; | |
| 89 | + } | |
| 90 | + objects.forEach(function(obj) { | |
| 91 | + for (const key in obj) { | |
| 92 | + result[key] = obj[key]; | |
| 93 | + } | |
| 94 | + }); | |
| 95 | + return /** @type {T} */ (result); | |
| 96 | +} | |
| 97 | + | |
| 98 | +/** | |
| 99 | + * @typedef {object} Renderer | |
| 100 | + * @property {(text: string) => void} addText | |
| 101 | + * @property {(node: Node) => void} openNode | |
| 102 | + * @property {(node: Node) => void} closeNode | |
| 103 | + * @property {() => string} value | |
| 104 | + */ | |
| 105 | + | |
| 106 | +/** @typedef {{scope?: string, language?: string, sublanguage?: boolean}} Node */ | |
| 107 | +/** @typedef {{walk: (r: Renderer) => void}} Tree */ | |
| 108 | +/** */ | |
| 109 | + | |
| 110 | +const SPAN_CLOSE = '</span>'; | |
| 111 | + | |
| 112 | +/** | |
| 113 | + * Determines if a node needs to be wrapped in <span> | |
| 114 | + * | |
| 115 | + * @param {Node} node */ | |
| 116 | +const emitsWrappingTags = (node) => { | |
| 117 | + // rarely we can have a sublanguage where language is undefined | |
| 118 | + // TODO: track down why | |
| 119 | + return !!node.scope; | |
| 120 | +}; | |
| 121 | + | |
| 122 | +/** | |
| 123 | + * | |
| 124 | + * @param {string} name | |
| 125 | + * @param {{prefix:string}} options | |
| 126 | + */ | |
| 127 | +const scopeToCSSClass = (name, { prefix }) => { | |
| 128 | + // sub-language | |
| 129 | + if (name.startsWith("language:")) { | |
| 130 | + return name.replace("language:", "language-"); | |
| 131 | + } | |
| 132 | + // tiered scope: comment.line | |
| 133 | + if (name.includes(".")) { | |
| 134 | + const pieces = name.split("."); | |
| 135 | + return [ | |
| 136 | + `${prefix}${pieces.shift()}`, | |
| 137 | + ...(pieces.map((x, i) => `${x}${"_".repeat(i + 1)}`)) | |
| 138 | + ].join(" "); | |
| 139 | + } | |
| 140 | + // simple scope | |
| 141 | + return `${prefix}${name}`; | |
| 142 | +}; | |
| 143 | + | |
| 144 | +/** @type {Renderer} */ | |
| 145 | +class HTMLRenderer { | |
| 146 | + /** | |
| 147 | + * Creates a new HTMLRenderer | |
| 148 | + * | |
| 149 | + * @param {Tree} parseTree - the parse tree (must support `walk` API) | |
| 150 | + * @param {{classPrefix: string}} options | |
| 151 | + */ | |
| 152 | + constructor(parseTree, options) { | |
| 153 | + this.buffer = ""; | |
| 154 | + this.classPrefix = options.classPrefix; | |
| 155 | + parseTree.walk(this); | |
| 156 | + } | |
| 157 | + | |
| 158 | + /** | |
| 159 | + * Adds texts to the output stream | |
| 160 | + * | |
| 161 | + * @param {string} text */ | |
| 162 | + addText(text) { | |
| 163 | + this.buffer += escapeHTML(text); | |
| 164 | + } | |
| 165 | + | |
| 166 | + /** | |
| 167 | + * Adds a node open to the output stream (if needed) | |
| 168 | + * | |
| 169 | + * @param {Node} node */ | |
| 170 | + openNode(node) { | |
| 171 | + if (!emitsWrappingTags(node)) return; | |
| 172 | + | |
| 173 | + const className = scopeToCSSClass(node.scope, | |
| 174 | + { prefix: this.classPrefix }); | |
| 175 | + this.span(className); | |
| 176 | + } | |
| 177 | + | |
| 178 | + /** | |
| 179 | + * Adds a node close to the output stream (if needed) | |
| 180 | + * | |
| 181 | + * @param {Node} node */ | |
| 182 | + closeNode(node) { | |
| 183 | + if (!emitsWrappingTags(node)) return; | |
| 184 | + | |
| 185 | + this.buffer += SPAN_CLOSE; | |
| 186 | + } | |
| 187 | + | |
| 188 | + /** | |
| 189 | + * returns the accumulated buffer | |
| 190 | + */ | |
| 191 | + value() { | |
| 192 | + return this.buffer; | |
| 193 | + } | |
| 194 | + | |
| 195 | + // helpers | |
| 196 | + | |
| 197 | + /** | |
| 198 | + * Builds a span element | |
| 199 | + * | |
| 200 | + * @param {string} className */ | |
| 201 | + span(className) { | |
| 202 | + this.buffer += `<span class="${className}">`; | |
| 203 | + } | |
| 204 | +} | |
| 205 | + | |
| 206 | +/** @typedef {{scope?: string, language?: string, children: Node[]} | string} Node */ | |
| 207 | +/** @typedef {{scope?: string, language?: string, children: Node[]} } DataNode */ | |
| 208 | +/** @typedef {import('highlight.js').Emitter} Emitter */ | |
| 209 | +/** */ | |
| 210 | + | |
| 211 | +/** @returns {DataNode} */ | |
| 212 | +const newNode = (opts = {}) => { | |
| 213 | + /** @type DataNode */ | |
| 214 | + const result = { children: [] }; | |
| 215 | + Object.assign(result, opts); | |
| 216 | + return result; | |
| 217 | +}; | |
| 218 | + | |
| 219 | +class TokenTree { | |
| 220 | + constructor() { | |
| 221 | + /** @type DataNode */ | |
| 222 | + this.rootNode = newNode(); | |
| 223 | + this.stack = [this.rootNode]; | |
| 224 | + } | |
| 225 | + | |
| 226 | + get top() { | |
| 227 | + return this.stack[this.stack.length - 1]; | |
| 228 | + } | |
| 229 | + | |
| 230 | + get root() { return this.rootNode; } | |
| 231 | + | |
| 232 | + /** @param {Node} node */ | |
| 233 | + add(node) { | |
| 234 | + this.top.children.push(node); | |
| 235 | + } | |
| 236 | + | |
| 237 | + /** @param {string} scope */ | |
| 238 | + openNode(scope) { | |
| 239 | + /** @type Node */ | |
| 240 | + const node = newNode({ scope }); | |
| 241 | + this.add(node); | |
| 242 | + this.stack.push(node); | |
| 243 | + } | |
| 244 | + | |
| 245 | + closeNode() { | |
| 246 | + if (this.stack.length > 1) { | |
| 247 | + return this.stack.pop(); | |
| 248 | + } | |
| 249 | + // eslint-disable-next-line no-undefined | |
| 250 | + return undefined; | |
| 251 | + } | |
| 252 | + | |
| 253 | + closeAllNodes() { | |
| 254 | + while (this.closeNode()); | |
| 255 | + } | |
| 256 | + | |
| 257 | + toJSON() { | |
| 258 | + return JSON.stringify(this.rootNode, null, 4); | |
| 259 | + } | |
| 260 | + | |
| 261 | + /** | |
| 262 | + * @typedef { import("./html_renderer").Renderer } Renderer | |
| 263 | + * @param {Renderer} builder | |
| 264 | + */ | |
| 265 | + walk(builder) { | |
| 266 | + // this does not | |
| 267 | + return this.constructor._walk(builder, this.rootNode); | |
| 268 | + // this works | |
| 269 | + // return TokenTree._walk(builder, this.rootNode); | |
| 270 | + } | |
| 271 | + | |
| 272 | + /** | |
| 273 | + * @param {Renderer} builder | |
| 274 | + * @param {Node} node | |
| 275 | + */ | |
| 276 | + static _walk(builder, node) { | |
| 277 | + if (typeof node === "string") { | |
| 278 | + builder.addText(node); | |
| 279 | + } else if (node.children) { | |
| 280 | + builder.openNode(node); | |
| 281 | + node.children.forEach((child) => this._walk(builder, child)); | |
| 282 | + builder.closeNode(node); | |
| 283 | + } | |
| 284 | + return builder; | |
| 285 | + } | |
| 286 | + | |
| 287 | + /** | |
| 288 | + * @param {Node} node | |
| 289 | + */ | |
| 290 | + static _collapse(node) { | |
| 291 | + if (typeof node === "string") return; | |
| 292 | + if (!node.children) return; | |
| 293 | + | |
| 294 | + if (node.children.every(el => typeof el === "string")) { | |
| 295 | + // node.text = node.children.join(""); | |
| 296 | + // delete node.children; | |
| 297 | + node.children = [node.children.join("")]; | |
| 298 | + } else { | |
| 299 | + node.children.forEach((child) => { | |
| 300 | + TokenTree._collapse(child); | |
| 301 | + }); | |
| 302 | + } | |
| 303 | + } | |
| 304 | +} | |
| 305 | + | |
| 306 | +/** | |
| 307 | + Currently this is all private API, but this is the minimal API necessary | |
| 308 | + that an Emitter must implement to fully support the parser. | |
| 309 | + | |
| 310 | + Minimal interface: | |
| 311 | + | |
| 312 | + - addText(text) | |
| 313 | + - __addSublanguage(emitter, subLanguageName) | |
| 314 | + - startScope(scope) | |
| 315 | + - endScope() | |
| 316 | + - finalize() | |
| 317 | + - toHTML() | |
| 318 | + | |
| 319 | +*/ | |
| 320 | + | |
| 321 | +/** | |
| 322 | + * @implements {Emitter} | |
| 323 | + */ | |
| 324 | +class TokenTreeEmitter extends TokenTree { | |
| 325 | + /** | |
| 326 | + * @param {*} options | |
| 327 | + */ | |
| 328 | + constructor(options) { | |
| 329 | + super(); | |
| 330 | + this.options = options; | |
| 331 | + } | |
| 332 | + | |
| 333 | + /** | |
| 334 | + * @param {string} text | |
| 335 | + */ | |
| 336 | + addText(text) { | |
| 337 | + if (text === "") { return; } | |
| 338 | + | |
| 339 | + this.add(text); | |
| 340 | + } | |
| 341 | + | |
| 342 | + /** @param {string} scope */ | |
| 343 | + startScope(scope) { | |
| 344 | + this.openNode(scope); | |
| 345 | + } | |
| 346 | + | |
| 347 | + endScope() { | |
| 348 | + this.closeNode(); | |
| 349 | + } | |
| 350 | + | |
| 351 | + /** | |
| 352 | + * @param {Emitter & {root: DataNode}} emitter | |
| 353 | + * @param {string} name | |
| 354 | + */ | |
| 355 | + __addSublanguage(emitter, name) { | |
| 356 | + /** @type DataNode */ | |
| 357 | + const node = emitter.root; | |
| 358 | + if (name) node.scope = `language:${name}`; | |
| 359 | + | |
| 360 | + this.add(node); | |
| 361 | + } | |
| 362 | + | |
| 363 | + toHTML() { | |
| 364 | + const renderer = new HTMLRenderer(this, this.options); | |
| 365 | + return renderer.value(); | |
| 366 | + } | |
| 367 | + | |
| 368 | + finalize() { | |
| 369 | + this.closeAllNodes(); | |
| 370 | + return true; | |
| 371 | + } | |
| 372 | +} | |
| 373 | + | |
| 374 | +/** | |
| 375 | + * @param {string} value | |
| 376 | + * @returns {RegExp} | |
| 377 | + * */ | |
| 378 | + | |
| 379 | +/** | |
| 380 | + * @param {RegExp | string } re | |
| 381 | + * @returns {string} | |
| 382 | + */ | |
| 383 | +function source(re) { | |
| 384 | + if (!re) return null; | |
| 385 | + if (typeof re === "string") return re; | |
| 386 | + | |
| 387 | + return re.source; | |
| 388 | +} | |
| 389 | + | |
| 390 | +/** | |
| 391 | + * @param {RegExp | string } re | |
| 392 | + * @returns {string} | |
| 393 | + */ | |
| 394 | +function lookahead(re) { | |
| 395 | + return concat('(?=', re, ')'); | |
| 396 | +} | |
| 397 | + | |
| 398 | +/** | |
| 399 | + * @param {RegExp | string } re | |
| 400 | + * @returns {string} | |
| 401 | + */ | |
| 402 | +function anyNumberOfTimes(re) { | |
| 403 | + return concat('(?:', re, ')*'); | |
| 404 | +} | |
| 405 | + | |
| 406 | +/** | |
| 407 | + * @param {RegExp | string } re | |
| 408 | + * @returns {string} | |
| 409 | + */ | |
| 410 | +function optional(re) { | |
| 411 | + return concat('(?:', re, ')?'); | |
| 412 | +} | |
| 413 | + | |
| 414 | +/** | |
| 415 | + * @param {...(RegExp | string) } args | |
| 416 | + * @returns {string} | |
| 417 | + */ | |
| 418 | +function concat(...args) { | |
| 419 | + const joined = args.map((x) => source(x)).join(""); | |
| 420 | + return joined; | |
| 421 | +} | |
| 422 | + | |
| 423 | +/** | |
| 424 | + * @param { Array<string | RegExp | Object> } args | |
| 425 | + * @returns {object} | |
| 426 | + */ | |
| 427 | +function stripOptionsFromArgs(args) { | |
| 428 | + const opts = args[args.length - 1]; | |
| 429 | + | |
| 430 | + if (typeof opts === 'object' && opts.constructor === Object) { | |
| 431 | + args.splice(args.length - 1, 1); | |
| 432 | + return opts; | |
| 433 | + } else { | |
| 434 | + return {}; | |
| 435 | + } | |
| 436 | +} | |
| 437 | + | |
| 438 | +/** @typedef { {capture?: boolean} } RegexEitherOptions */ | |
| 439 | + | |
| 440 | +/** | |
| 441 | + * Any of the passed expresssions may match | |
| 442 | + * | |
| 443 | + * Creates a huge this | this | that | that match | |
| 444 | + * @param {(RegExp | string)[] | [...(RegExp | string)[], RegexEitherOptions]} args | |
| 445 | + * @returns {string} | |
| 446 | + */ | |
| 447 | +function either(...args) { | |
| 448 | + /** @type { object & {capture?: boolean} } */ | |
| 449 | + const opts = stripOptionsFromArgs(args); | |
| 450 | + const joined = '(' | |
| 451 | + + (opts.capture ? "" : "?:") | |
| 452 | + + args.map((x) => source(x)).join("|") + ")"; | |
| 453 | + return joined; | |
| 454 | +} | |
| 455 | + | |
| 456 | +/** | |
| 457 | + * @param {RegExp | string} re | |
| 458 | + * @returns {number} | |
| 459 | + */ | |
| 460 | +function countMatchGroups(re) { | |
| 461 | + return (new RegExp(re.toString() + '|')).exec('').length - 1; | |
| 462 | +} | |
| 463 | + | |
| 464 | +/** | |
| 465 | + * Does lexeme start with a regular expression match at the beginning | |
| 466 | + * @param {RegExp} re | |
| 467 | + * @param {string} lexeme | |
| 468 | + */ | |
| 469 | +function startsWith(re, lexeme) { | |
| 470 | + const match = re && re.exec(lexeme); | |
| 471 | + return match && match.index === 0; | |
| 472 | +} | |
| 473 | + | |
| 474 | +// BACKREF_RE matches an open parenthesis or backreference. To avoid | |
| 475 | +// an incorrect parse, it additionally matches the following: | |
| 476 | +// - [...] elements, where the meaning of parentheses and escapes change | |
| 477 | +// - other escape sequences, so we do not misparse escape sequences as | |
| 478 | +// interesting elements | |
| 479 | +// - non-matching or lookahead parentheses, which do not capture. These | |
| 480 | +// follow the '(' with a '?'. | |
| 481 | +const BACKREF_RE = /\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./; | |
| 482 | + | |
| 483 | +// **INTERNAL** Not intended for outside usage | |
| 484 | +// join logically computes regexps.join(separator), but fixes the | |
| 485 | +// backreferences so they continue to match. | |
| 486 | +// it also places each individual regular expression into it's own | |
| 487 | +// match group, keeping track of the sequencing of those match groups | |
| 488 | +// is currently an exercise for the caller. :-) | |
| 489 | +/** | |
| 490 | + * @param {(string | RegExp)[]} regexps | |
| 491 | + * @param {{joinWith: string}} opts | |
| 492 | + * @returns {string} | |
| 493 | + */ | |
| 494 | +function _rewriteBackreferences(regexps, { joinWith }) { | |
| 495 | + let numCaptures = 0; | |
| 496 | + | |
| 497 | + return regexps.map((regex) => { | |
| 498 | + numCaptures += 1; | |
| 499 | + const offset = numCaptures; | |
| 500 | + let re = source(regex); | |
| 501 | + let out = ''; | |
| 502 | + | |
| 503 | + while (re.length > 0) { | |
| 504 | + const match = BACKREF_RE.exec(re); | |
| 505 | + if (!match) { | |
| 506 | + out += re; | |
| 507 | + break; | |
| 508 | + } | |
| 509 | + out += re.substring(0, match.index); | |
| 510 | + re = re.substring(match.index + match[0].length); | |
| 511 | + if (match[0][0] === '\\' && match[1]) { | |
| 512 | + // Adjust the backreference. | |
| 513 | + out += '\\' + String(Number(match[1]) + offset); | |
| 514 | + } else { | |
| 515 | + out += match[0]; | |
| 516 | + if (match[0] === '(') { | |
| 517 | + numCaptures++; | |
| 518 | + } | |
| 519 | + } | |
| 520 | + } | |
| 521 | + return out; | |
| 522 | + }).map(re => `(${re})`).join(joinWith); | |
| 523 | +} | |
| 524 | + | |
| 525 | +/** @typedef {import('highlight.js').Mode} Mode */ | |
| 526 | +/** @typedef {import('highlight.js').ModeCallback} ModeCallback */ | |
| 527 | + | |
| 528 | +// Common regexps | |
| 529 | +const MATCH_NOTHING_RE = /\b\B/; | |
| 530 | +const IDENT_RE = '[a-zA-Z]\\w*'; | |
| 531 | +const UNDERSCORE_IDENT_RE = '[a-zA-Z_]\\w*'; | |
| 532 | +const NUMBER_RE = '\\b\\d+(\\.\\d+)?'; | |
| 533 | +const C_NUMBER_RE = '(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)'; // 0x..., 0..., decimal, float | |
| 534 | +const BINARY_NUMBER_RE = '\\b(0b[01]+)'; // 0b... | |
| 535 | +const RE_STARTERS_RE = '!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~'; | |
| 536 | + | |
| 537 | +/** | |
| 538 | +* @param { Partial<Mode> & {binary?: string | RegExp} } opts | |
| 539 | +*/ | |
| 540 | +const SHEBANG = (opts = {}) => { | |
| 541 | + const beginShebang = /^#![ ]*\//; | |
| 542 | + if (opts.binary) { | |
| 543 | + opts.begin = concat( | |
| 544 | + beginShebang, | |
| 545 | + /.*\b/, | |
| 546 | + opts.binary, | |
| 547 | + /\b.*/); | |
| 548 | + } | |
| 549 | + return inherit$1({ | |
| 550 | + scope: 'meta', | |
| 551 | + begin: beginShebang, | |
| 552 | + end: /$/, | |
| 553 | + relevance: 0, | |
| 554 | + /** @type {ModeCallback} */ | |
| 555 | + "on:begin": (m, resp) => { | |
| 556 | + if (m.index !== 0) resp.ignoreMatch(); | |
| 557 | + } | |
| 558 | + }, opts); | |
| 559 | +}; | |
| 560 | + | |
| 561 | +// Common modes | |
| 562 | +const BACKSLASH_ESCAPE = { | |
| 563 | + begin: '\\\\[\\s\\S]', relevance: 0 | |
| 564 | +}; | |
| 565 | +const APOS_STRING_MODE = { | |
| 566 | + scope: 'string', | |
| 567 | + begin: '\'', | |
| 568 | + end: '\'', | |
| 569 | + illegal: '\\n', | |
| 570 | + contains: [BACKSLASH_ESCAPE] | |
| 571 | +}; | |
| 572 | +const QUOTE_STRING_MODE = { | |
| 573 | + scope: 'string', | |
| 574 | + begin: '"', | |
| 575 | + end: '"', | |
| 576 | + illegal: '\\n', | |
| 577 | + contains: [BACKSLASH_ESCAPE] | |
| 578 | +}; | |
| 579 | +const PHRASAL_WORDS_MODE = { | |
| 580 | + begin: /\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ | |
| 581 | +}; | |
| 582 | +/** | |
| 583 | + * Creates a comment mode | |
| 584 | + * | |
| 585 | + * @param {string | RegExp} begin | |
| 586 | + * @param {string | RegExp} end | |
| 587 | + * @param {Mode | {}} [modeOptions] | |
| 588 | + * @returns {Partial<Mode>} | |
| 589 | + */ | |
| 590 | +const COMMENT = function(begin, end, modeOptions = {}) { | |
| 591 | + const mode = inherit$1( | |
| 592 | + { | |
| 593 | + scope: 'comment', | |
| 594 | + begin, | |
| 595 | + end, | |
| 596 | + contains: [] | |
| 597 | + }, | |
| 598 | + modeOptions | |
| 599 | + ); | |
| 600 | + mode.contains.push({ | |
| 601 | + scope: 'doctag', | |
| 602 | + // hack to avoid the space from being included. the space is necessary to | |
| 603 | + // match here to prevent the plain text rule below from gobbling up doctags | |
| 604 | + begin: '[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)', | |
| 605 | + end: /(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/, | |
| 606 | + excludeBegin: true, | |
| 607 | + relevance: 0 | |
| 608 | + }); | |
| 609 | + const ENGLISH_WORD = either( | |
| 610 | + // list of common 1 and 2 letter words in English | |
| 611 | + "I", | |
| 612 | + "a", | |
| 613 | + "is", | |
| 614 | + "so", | |
| 615 | + "us", | |
| 616 | + "to", | |
| 617 | + "at", | |
| 618 | + "if", | |
| 619 | + "in", | |
| 620 | + "it", | |
| 621 | + "on", | |
| 622 | + // note: this is not an exhaustive list of contractions, just popular ones | |
| 623 | + /[A-Za-z]+['](d|ve|re|ll|t|s|n)/, // contractions - can't we'd they're let's, etc | |
| 624 | + /[A-Za-z]+[-][a-z]+/, // `no-way`, etc. | |
| 625 | + /[A-Za-z][a-z]{2,}/ // allow capitalized words at beginning of sentences | |
| 626 | + ); | |
| 627 | + // looking like plain text, more likely to be a comment | |
| 628 | + mode.contains.push( | |
| 629 | + { | |
| 630 | + // TODO: how to include ", (, ) without breaking grammars that use these for | |
| 631 | + // comment delimiters? | |
| 632 | + // begin: /[ ]+([()"]?([A-Za-z'-]{3,}|is|a|I|so|us|[tT][oO]|at|if|in|it|on)[.]?[()":]?([.][ ]|[ ]|\))){3}/ | |
| 633 | + // --- | |
| 634 | + | |
| 635 | + // this tries to find sequences of 3 english words in a row (without any | |
| 636 | + // "programming" type syntax) this gives us a strong signal that we've | |
| 637 | + // TRULY found a comment - vs perhaps scanning with the wrong language. | |
| 638 | + // It's possible to find something that LOOKS like the start of the | |
| 639 | + // comment - but then if there is no readable text - good chance it is a | |
| 640 | + // false match and not a comment. | |
| 641 | + // | |
| 642 | + // for a visual example please see: | |
| 643 | + // https://github.com/highlightjs/highlight.js/issues/2827 | |
| 644 | + | |
| 645 | + begin: concat( | |
| 646 | + /[ ]+/, // necessary to prevent us gobbling up doctags like /* @author Bob Mcgill */ | |
| 647 | + '(', | |
| 648 | + ENGLISH_WORD, | |
| 649 | + /[.]?[:]?([.][ ]|[ ])/, | |
| 650 | + '){3}') // look for 3 words in a row | |
| 651 | + } | |
| 652 | + ); | |
| 653 | + return mode; | |
| 654 | +}; | |
| 655 | +const C_LINE_COMMENT_MODE = COMMENT('//', '$'); | |
| 656 | +const C_BLOCK_COMMENT_MODE = COMMENT('/\\*', '\\*/'); | |
| 657 | +const HASH_COMMENT_MODE = COMMENT('#', '$'); | |
| 658 | +const NUMBER_MODE = { | |
| 659 | + scope: 'number', | |
| 660 | + begin: NUMBER_RE, | |
| 661 | + relevance: 0 | |
| 662 | +}; | |
| 663 | +const C_NUMBER_MODE = { | |
| 664 | + scope: 'number', | |
| 665 | + begin: C_NUMBER_RE, | |
| 666 | + relevance: 0 | |
| 667 | +}; | |
| 668 | +const BINARY_NUMBER_MODE = { | |
| 669 | + scope: 'number', | |
| 670 | + begin: BINARY_NUMBER_RE, | |
| 671 | + relevance: 0 | |
| 672 | +}; | |
| 673 | +const REGEXP_MODE = { | |
| 674 | + scope: "regexp", | |
| 675 | + begin: /\/(?=[^/\n]*\/)/, | |
| 676 | + end: /\/[gimuy]*/, | |
| 677 | + contains: [ | |
| 678 | + BACKSLASH_ESCAPE, | |
| 679 | + { | |
| 680 | + begin: /\[/, | |
| 681 | + end: /\]/, | |
| 682 | + relevance: 0, | |
| 683 | + contains: [BACKSLASH_ESCAPE] | |
| 684 | + } | |
| 685 | + ] | |
| 686 | +}; | |
| 687 | +const TITLE_MODE = { | |
| 688 | + scope: 'title', | |
| 689 | + begin: IDENT_RE, | |
| 690 | + relevance: 0 | |
| 691 | +}; | |
| 692 | +const UNDERSCORE_TITLE_MODE = { | |
| 693 | + scope: 'title', | |
| 694 | + begin: UNDERSCORE_IDENT_RE, | |
| 695 | + relevance: 0 | |
| 696 | +}; | |
| 697 | +const METHOD_GUARD = { | |
| 698 | + // excludes method names from keyword processing | |
| 699 | + begin: '\\.\\s*' + UNDERSCORE_IDENT_RE, | |
| 700 | + relevance: 0 | |
| 701 | +}; | |
| 702 | + | |
| 703 | +/** | |
| 704 | + * Adds end same as begin mechanics to a mode | |
| 705 | + * | |
| 706 | + * Your mode must include at least a single () match group as that first match | |
| 707 | + * group is what is used for comparison | |
| 708 | + * @param {Partial<Mode>} mode | |
| 709 | + */ | |
| 710 | +const END_SAME_AS_BEGIN = function(mode) { | |
| 711 | + return Object.assign(mode, | |
| 712 | + { | |
| 713 | + /** @type {ModeCallback} */ | |
| 714 | + 'on:begin': (m, resp) => { resp.data._beginMatch = m[1]; }, | |
| 715 | + /** @type {ModeCallback} */ | |
| 716 | + 'on:end': (m, resp) => { if (resp.data._beginMatch !== m[1]) resp.ignoreMatch(); } | |
| 717 | + }); | |
| 718 | +}; | |
| 719 | + | |
| 720 | +var MODES = /*#__PURE__*/Object.freeze({ | |
| 721 | + __proto__: null, | |
| 722 | + APOS_STRING_MODE: APOS_STRING_MODE, | |
| 723 | + BACKSLASH_ESCAPE: BACKSLASH_ESCAPE, | |
| 724 | + BINARY_NUMBER_MODE: BINARY_NUMBER_MODE, | |
| 725 | + BINARY_NUMBER_RE: BINARY_NUMBER_RE, | |
| 726 | + COMMENT: COMMENT, | |
| 727 | + C_BLOCK_COMMENT_MODE: C_BLOCK_COMMENT_MODE, | |
| 728 | + C_LINE_COMMENT_MODE: C_LINE_COMMENT_MODE, | |
| 729 | + C_NUMBER_MODE: C_NUMBER_MODE, | |
| 730 | + C_NUMBER_RE: C_NUMBER_RE, | |
| 731 | + END_SAME_AS_BEGIN: END_SAME_AS_BEGIN, | |
| 732 | + HASH_COMMENT_MODE: HASH_COMMENT_MODE, | |
| 733 | + IDENT_RE: IDENT_RE, | |
| 734 | + MATCH_NOTHING_RE: MATCH_NOTHING_RE, | |
| 735 | + METHOD_GUARD: METHOD_GUARD, | |
| 736 | + NUMBER_MODE: NUMBER_MODE, | |
| 737 | + NUMBER_RE: NUMBER_RE, | |
| 738 | + PHRASAL_WORDS_MODE: PHRASAL_WORDS_MODE, | |
| 739 | + QUOTE_STRING_MODE: QUOTE_STRING_MODE, | |
| 740 | + REGEXP_MODE: REGEXP_MODE, | |
| 741 | + RE_STARTERS_RE: RE_STARTERS_RE, | |
| 742 | + SHEBANG: SHEBANG, | |
| 743 | + TITLE_MODE: TITLE_MODE, | |
| 744 | + UNDERSCORE_IDENT_RE: UNDERSCORE_IDENT_RE, | |
| 745 | + UNDERSCORE_TITLE_MODE: UNDERSCORE_TITLE_MODE | |
| 746 | +}); | |
| 747 | + | |
| 748 | +/** | |
| 749 | +@typedef {import('highlight.js').CallbackResponse} CallbackResponse | |
| 750 | +@typedef {import('highlight.js').CompilerExt} CompilerExt | |
| 751 | +*/ | |
| 752 | + | |
| 753 | +// Grammar extensions / plugins | |
| 754 | +// See: https://github.com/highlightjs/highlight.js/issues/2833 | |
| 755 | + | |
| 756 | +// Grammar extensions allow "syntactic sugar" to be added to the grammar modes | |
| 757 | +// without requiring any underlying changes to the compiler internals. | |
| 758 | + | |
| 759 | +// `compileMatch` being the perfect small example of now allowing a grammar | |
| 760 | +// author to write `match` when they desire to match a single expression rather | |
| 761 | +// than being forced to use `begin`. The extension then just moves `match` into | |
| 762 | +// `begin` when it runs. Ie, no features have been added, but we've just made | |
| 763 | +// the experience of writing (and reading grammars) a little bit nicer. | |
| 764 | + | |
| 765 | +// ------ | |
| 766 | + | |
| 767 | +// TODO: We need negative look-behind support to do this properly | |
| 768 | +/** | |
| 769 | + * Skip a match if it has a preceding dot | |
| 770 | + * | |
| 771 | + * This is used for `beginKeywords` to prevent matching expressions such as | |
| 772 | + * `bob.keyword.do()`. The mode compiler automatically wires this up as a | |
| 773 | + * special _internal_ 'on:begin' callback for modes with `beginKeywords` | |
| 774 | + * @param {RegExpMatchArray} match | |
| 775 | + * @param {CallbackResponse} response | |
| 776 | + */ | |
| 777 | +function skipIfHasPrecedingDot(match, response) { | |
| 778 | + const before = match.input[match.index - 1]; | |
| 779 | + if (before === ".") { | |
| 780 | + response.ignoreMatch(); | |
| 781 | + } | |
| 782 | +} | |
| 783 | + | |
| 784 | +/** | |
| 785 | + * | |
| 786 | + * @type {CompilerExt} | |
| 787 | + */ | |
| 788 | +function scopeClassName(mode, _parent) { | |
| 789 | + // eslint-disable-next-line no-undefined | |
| 790 | + if (mode.className !== undefined) { | |
| 791 | + mode.scope = mode.className; | |
| 792 | + delete mode.className; | |
| 793 | + } | |
| 794 | +} | |
| 795 | + | |
| 796 | +/** | |
| 797 | + * `beginKeywords` syntactic sugar | |
| 798 | + * @type {CompilerExt} | |
| 799 | + */ | |
| 800 | +function beginKeywords(mode, parent) { | |
| 801 | + if (!parent) return; | |
| 802 | + if (!mode.beginKeywords) return; | |
| 803 | + | |
| 804 | + // for languages with keywords that include non-word characters checking for | |
| 805 | + // a word boundary is not sufficient, so instead we check for a word boundary | |
| 806 | + // or whitespace - this does no harm in any case since our keyword engine | |
| 807 | + // doesn't allow spaces in keywords anyways and we still check for the boundary | |
| 808 | + // first | |
| 809 | + mode.begin = '\\b(' + mode.beginKeywords.split(' ').join('|') + ')(?!\\.)(?=\\b|\\s)'; | |
| 810 | + mode.__beforeBegin = skipIfHasPrecedingDot; | |
| 811 | + mode.keywords = mode.keywords || mode.beginKeywords; | |
| 812 | + delete mode.beginKeywords; | |
| 813 | + | |
| 814 | + // prevents double relevance, the keywords themselves provide | |
| 815 | + // relevance, the mode doesn't need to double it | |
| 816 | + // eslint-disable-next-line no-undefined | |
| 817 | + if (mode.relevance === undefined) mode.relevance = 0; | |
| 818 | +} | |
| 819 | + | |
| 820 | +/** | |
| 821 | + * Allow `illegal` to contain an array of illegal values | |
| 822 | + * @type {CompilerExt} | |
| 823 | + */ | |
| 824 | +function compileIllegal(mode, _parent) { | |
| 825 | + if (!Array.isArray(mode.illegal)) return; | |
| 826 | + | |
| 827 | + mode.illegal = either(...mode.illegal); | |
| 828 | +} | |
| 829 | + | |
| 830 | +/** | |
| 831 | + * `match` to match a single expression for readability | |
| 832 | + * @type {CompilerExt} | |
| 833 | + */ | |
| 834 | +function compileMatch(mode, _parent) { | |
| 835 | + if (!mode.match) return; | |
| 836 | + if (mode.begin || mode.end) throw new Error("begin & end are not supported with match"); | |
| 837 | + | |
| 838 | + mode.begin = mode.match; | |
| 839 | + delete mode.match; | |
| 840 | +} | |
| 841 | + | |
| 842 | +/** | |
| 843 | + * provides the default 1 relevance to all modes | |
| 844 | + * @type {CompilerExt} | |
| 845 | + */ | |
| 846 | +function compileRelevance(mode, _parent) { | |
| 847 | + // eslint-disable-next-line no-undefined | |
| 848 | + if (mode.relevance === undefined) mode.relevance = 1; | |
| 849 | +} | |
| 850 | + | |
| 851 | +// allow beforeMatch to act as a "qualifier" for the match | |
| 852 | +// the full match begin must be [beforeMatch][begin] | |
| 853 | +const beforeMatchExt = (mode, parent) => { | |
| 854 | + if (!mode.beforeMatch) return; | |
| 855 | + // starts conflicts with endsParent which we need to make sure the child | |
| 856 | + // rule is not matched multiple times | |
| 857 | + if (mode.starts) throw new Error("beforeMatch cannot be used with starts"); | |
| 858 | + | |
| 859 | + const originalMode = Object.assign({}, mode); | |
| 860 | + Object.keys(mode).forEach((key) => { delete mode[key]; }); | |
| 861 | + | |
| 862 | + mode.keywords = originalMode.keywords; | |
| 863 | + mode.begin = concat(originalMode.beforeMatch, lookahead(originalMode.begin)); | |
| 864 | + mode.starts = { | |
| 865 | + relevance: 0, | |
| 866 | + contains: [ | |
| 867 | + Object.assign(originalMode, { endsParent: true }) | |
| 868 | + ] | |
| 869 | + }; | |
| 870 | + mode.relevance = 0; | |
| 871 | + | |
| 872 | + delete originalMode.beforeMatch; | |
| 873 | +}; | |
| 874 | + | |
| 875 | +// keywords that should have no default relevance value | |
| 876 | +const COMMON_KEYWORDS = [ | |
| 877 | + 'of', | |
| 878 | + 'and', | |
| 879 | + 'for', | |
| 880 | + 'in', | |
| 881 | + 'not', | |
| 882 | + 'or', | |
| 883 | + 'if', | |
| 884 | + 'then', | |
| 885 | + 'parent', // common variable name | |
| 886 | + 'list', // common variable name | |
| 887 | + 'value' // common variable name | |
| 888 | +]; | |
| 889 | + | |
| 890 | +const DEFAULT_KEYWORD_SCOPE = "keyword"; | |
| 891 | + | |
| 892 | +/** | |
| 893 | + * Given raw keywords from a language definition, compile them. | |
| 894 | + * | |
| 895 | + * @param {string | Record<string,string|string[]> | Array<string>} rawKeywords | |
| 896 | + * @param {boolean} caseInsensitive | |
| 897 | + */ | |
| 898 | +function compileKeywords(rawKeywords, caseInsensitive, scopeName = DEFAULT_KEYWORD_SCOPE) { | |
| 899 | + /** @type {import("highlight.js/private").KeywordDict} */ | |
| 900 | + const compiledKeywords = Object.create(null); | |
| 901 | + | |
| 902 | + // input can be a string of keywords, an array of keywords, or a object with | |
| 903 | + // named keys representing scopeName (which can then point to a string or array) | |
| 904 | + if (typeof rawKeywords === 'string') { | |
| 905 | + compileList(scopeName, rawKeywords.split(" ")); | |
| 906 | + } else if (Array.isArray(rawKeywords)) { | |
| 907 | + compileList(scopeName, rawKeywords); | |
| 908 | + } else { | |
| 909 | + Object.keys(rawKeywords).forEach(function(scopeName) { | |
| 910 | + // collapse all our objects back into the parent object | |
| 911 | + Object.assign( | |
| 912 | + compiledKeywords, | |
| 913 | + compileKeywords(rawKeywords[scopeName], caseInsensitive, scopeName) | |
| 914 | + ); | |
| 915 | + }); | |
| 916 | + } | |
| 917 | + return compiledKeywords; | |
| 918 | + | |
| 919 | + // --- | |
| 920 | + | |
| 921 | + /** | |
| 922 | + * Compiles an individual list of keywords | |
| 923 | + * | |
| 924 | + * Ex: "for if when while|5" | |
| 925 | + * | |
| 926 | + * @param {string} scopeName | |
| 927 | + * @param {Array<string>} keywordList | |
| 928 | + */ | |
| 929 | + function compileList(scopeName, keywordList) { | |
| 930 | + if (caseInsensitive) { | |
| 931 | + keywordList = keywordList.map(x => x.toLowerCase()); | |
| 932 | + } | |
| 933 | + keywordList.forEach(function(keyword) { | |
| 934 | + const pair = keyword.split('|'); | |
| 935 | + compiledKeywords[pair[0]] = [scopeName, scoreForKeyword(pair[0], pair[1])]; | |
| 936 | + }); | |
| 937 | + } | |
| 938 | +} | |
| 939 | + | |
| 940 | +/** | |
| 941 | + * Returns the proper score for a given keyword | |
| 942 | + * | |
| 943 | + * Also takes into account comment keywords, which will be scored 0 UNLESS | |
| 944 | + * another score has been manually assigned. | |
| 945 | + * @param {string} keyword | |
| 946 | + * @param {string} [providedScore] | |
| 947 | + */ | |
| 948 | +function scoreForKeyword(keyword, providedScore) { | |
| 949 | + // manual scores always win over common keywords | |
| 950 | + // so you can force a score of 1 if you really insist | |
| 951 | + if (providedScore) { | |
| 952 | + return Number(providedScore); | |
| 953 | + } | |
| 954 | + | |
| 955 | + return commonKeyword(keyword) ? 0 : 1; | |
| 956 | +} | |
| 957 | + | |
| 958 | +/** | |
| 959 | + * Determines if a given keyword is common or not | |
| 960 | + * | |
| 961 | + * @param {string} keyword */ | |
| 962 | +function commonKeyword(keyword) { | |
| 963 | + return COMMON_KEYWORDS.includes(keyword.toLowerCase()); | |
| 964 | +} | |
| 965 | + | |
| 966 | +/* | |
| 967 | + | |
| 968 | +For the reasoning behind this please see: | |
| 969 | +https://github.com/highlightjs/highlight.js/issues/2880#issuecomment-747275419 | |
| 970 | + | |
| 971 | +*/ | |
| 972 | + | |
| 973 | +/** | |
| 974 | + * @type {Record<string, boolean>} | |
| 975 | + */ | |
| 976 | +const seenDeprecations = {}; | |
| 977 | + | |
| 978 | +/** | |
| 979 | + * @param {string} message | |
| 980 | + */ | |
| 981 | +const error = (message) => { | |
| 982 | + console.error(message); | |
| 983 | +}; | |
| 984 | + | |
| 985 | +/** | |
| 986 | + * @param {string} message | |
| 987 | + * @param {any} args | |
| 988 | + */ | |
| 989 | +const warn = (message, ...args) => { | |
| 990 | + console.log(`WARN: ${message}`, ...args); | |
| 991 | +}; | |
| 992 | + | |
| 993 | +/** | |
| 994 | + * @param {string} version | |
| 995 | + * @param {string} message | |
| 996 | + */ | |
| 997 | +const deprecated = (version, message) => { | |
| 998 | + if (seenDeprecations[`${version}/${message}`]) return; | |
| 999 | + | |
| 1000 | + console.log(`Deprecated as of ${version}. ${message}`); | |
| 1001 | + seenDeprecations[`${version}/${message}`] = true; | |
| 1002 | +}; | |
| 1003 | + | |
| 1004 | +/* eslint-disable no-throw-literal */ | |
| 1005 | + | |
| 1006 | +/** | |
| 1007 | +@typedef {import('highlight.js').CompiledMode} CompiledMode | |
| 1008 | +*/ | |
| 1009 | + | |
| 1010 | +const MultiClassError = new Error(); | |
| 1011 | + | |
| 1012 | +/** | |
| 1013 | + * Renumbers labeled scope names to account for additional inner match | |
| 1014 | + * groups that otherwise would break everything. | |
| 1015 | + * | |
| 1016 | + * Lets say we 3 match scopes: | |
| 1017 | + * | |
| 1018 | + * { 1 => ..., 2 => ..., 3 => ... } | |
| 1019 | + * | |
| 1020 | + * So what we need is a clean match like this: | |
| 1021 | + * | |
| 1022 | + * (a)(b)(c) => [ "a", "b", "c" ] | |
| 1023 | + * | |
| 1024 | + * But this falls apart with inner match groups: | |
| 1025 | + * | |
| 1026 | + * (a)(((b)))(c) => ["a", "b", "b", "b", "c" ] | |
| 1027 | + * | |
| 1028 | + * Our scopes are now "out of alignment" and we're repeating `b` 3 times. | |
| 1029 | + * What needs to happen is the numbers are remapped: | |
| 1030 | + * | |
| 1031 | + * { 1 => ..., 2 => ..., 5 => ... } | |
| 1032 | + * | |
| 1033 | + * We also need to know that the ONLY groups that should be output | |
| 1034 | + * are 1, 2, and 5. This function handles this behavior. | |
| 1035 | + * | |
| 1036 | + * @param {CompiledMode} mode | |
| 1037 | + * @param {Array<RegExp | string>} regexes | |
| 1038 | + * @param {{key: "beginScope"|"endScope"}} opts | |
| 1039 | + */ | |
| 1040 | +function remapScopeNames(mode, regexes, { key }) { | |
| 1041 | + let offset = 0; | |
| 1042 | + const scopeNames = mode[key]; | |
| 1043 | + /** @type Record<number,boolean> */ | |
| 1044 | + const emit = {}; | |
| 1045 | + /** @type Record<number,string> */ | |
| 1046 | + const positions = {}; | |
| 1047 | + | |
| 1048 | + for (let i = 1; i <= regexes.length; i++) { | |
| 1049 | + positions[i + offset] = scopeNames[i]; | |
| 1050 | + emit[i + offset] = true; | |
| 1051 | + offset += countMatchGroups(regexes[i - 1]); | |
| 1052 | + } | |
| 1053 | + // we use _emit to keep track of which match groups are "top-level" to avoid double | |
| 1054 | + // output from inside match groups | |
| 1055 | + mode[key] = positions; | |
| 1056 | + mode[key]._emit = emit; | |
| 1057 | + mode[key]._multi = true; | |
| 1058 | +} | |
| 1059 | + | |
| 1060 | +/** | |
| 1061 | + * @param {CompiledMode} mode | |
| 1062 | + */ | |
| 1063 | +function beginMultiClass(mode) { | |
| 1064 | + if (!Array.isArray(mode.begin)) return; | |
| 1065 | + | |
| 1066 | + if (mode.skip || mode.excludeBegin || mode.returnBegin) { | |
| 1067 | + error("skip, excludeBegin, returnBegin not compatible with beginScope: {}"); | |
| 1068 | + throw MultiClassError; | |
| 1069 | + } | |
| 1070 | + | |
| 1071 | + if (typeof mode.beginScope !== "object" || mode.beginScope === null) { | |
| 1072 | + error("beginScope must be object"); | |
| 1073 | + throw MultiClassError; | |
| 1074 | + } | |
| 1075 | + | |
| 1076 | + remapScopeNames(mode, mode.begin, { key: "beginScope" }); | |
| 1077 | + mode.begin = _rewriteBackreferences(mode.begin, { joinWith: "" }); | |
| 1078 | +} | |
| 1079 | + | |
| 1080 | +/** | |
| 1081 | + * @param {CompiledMode} mode | |
| 1082 | + */ | |
| 1083 | +function endMultiClass(mode) { | |
| 1084 | + if (!Array.isArray(mode.end)) return; | |
| 1085 | + | |
| 1086 | + if (mode.skip || mode.excludeEnd || mode.returnEnd) { | |
| 1087 | + error("skip, excludeEnd, returnEnd not compatible with endScope: {}"); | |
| 1088 | + throw MultiClassError; | |
| 1089 | + } | |
| 1090 | + | |
| 1091 | + if (typeof mode.endScope !== "object" || mode.endScope === null) { | |
| 1092 | + error("endScope must be object"); | |
| 1093 | + throw MultiClassError; | |
| 1094 | + } | |
| 1095 | + | |
| 1096 | + remapScopeNames(mode, mode.end, { key: "endScope" }); | |
| 1097 | + mode.end = _rewriteBackreferences(mode.end, { joinWith: "" }); | |
| 1098 | +} | |
| 1099 | + | |
| 1100 | +/** | |
| 1101 | + * this exists only to allow `scope: {}` to be used beside `match:` | |
| 1102 | + * Otherwise `beginScope` would necessary and that would look weird | |
| 1103 | + | |
| 1104 | + { | |
| 1105 | + match: [ /def/, /\w+/ ] | |
| 1106 | + scope: { 1: "keyword" , 2: "title" } | |
| 1107 | + } | |
| 1108 | + | |
| 1109 | + * @param {CompiledMode} mode | |
| 1110 | + */ | |
| 1111 | +function scopeSugar(mode) { | |
| 1112 | + if (mode.scope && typeof mode.scope === "object" && mode.scope !== null) { | |
| 1113 | + mode.beginScope = mode.scope; | |
| 1114 | + delete mode.scope; | |
| 1115 | + } | |
| 1116 | +} | |
| 1117 | + | |
| 1118 | +/** | |
| 1119 | + * @param {CompiledMode} mode | |
| 1120 | + */ | |
| 1121 | +function MultiClass(mode) { | |
| 1122 | + scopeSugar(mode); | |
| 1123 | + | |
| 1124 | + if (typeof mode.beginScope === "string") { | |
| 1125 | + mode.beginScope = { _wrap: mode.beginScope }; | |
| 1126 | + } | |
| 1127 | + if (typeof mode.endScope === "string") { | |
| 1128 | + mode.endScope = { _wrap: mode.endScope }; | |
| 1129 | + } | |
| 1130 | + | |
| 1131 | + beginMultiClass(mode); | |
| 1132 | + endMultiClass(mode); | |
| 1133 | +} | |
| 1134 | + | |
| 1135 | +/** | |
| 1136 | +@typedef {import('highlight.js').Mode} Mode | |
| 1137 | +@typedef {import('highlight.js').CompiledMode} CompiledMode | |
| 1138 | +@typedef {import('highlight.js').Language} Language | |
| 1139 | +@typedef {import('highlight.js').HLJSPlugin} HLJSPlugin | |
| 1140 | +@typedef {import('highlight.js').CompiledLanguage} CompiledLanguage | |
| 1141 | +*/ | |
| 1142 | + | |
| 1143 | +// compilation | |
| 1144 | + | |
| 1145 | +/** | |
| 1146 | + * Compiles a language definition result | |
| 1147 | + * | |
| 1148 | + * Given the raw result of a language definition (Language), compiles this so | |
| 1149 | + * that it is ready for highlighting code. | |
| 1150 | + * @param {Language} language | |
| 1151 | + * @returns {CompiledLanguage} | |
| 1152 | + */ | |
| 1153 | +function compileLanguage(language) { | |
| 1154 | + /** | |
| 1155 | + * Builds a regex with the case sensitivity of the current language | |
| 1156 | + * | |
| 1157 | + * @param {RegExp | string} value | |
| 1158 | + * @param {boolean} [global] | |
| 1159 | + */ | |
| 1160 | + function langRe(value, global) { | |
| 1161 | + return new RegExp( | |
| 1162 | + source(value), | |
| 1163 | + 'm' | |
| 1164 | + + (language.case_insensitive ? 'i' : '') | |
| 1165 | + + (language.unicodeRegex ? 'u' : '') | |
| 1166 | + + (global ? 'g' : '') | |
| 1167 | + ); | |
| 1168 | + } | |
| 1169 | + | |
| 1170 | + /** | |
| 1171 | + Stores multiple regular expressions and allows you to quickly search for | |
| 1172 | + them all in a string simultaneously - returning the first match. It does | |
| 1173 | + this by creating a huge (a|b|c) regex - each individual item wrapped with () | |
| 1174 | + and joined by `|` - using match groups to track position. When a match is | |
| 1175 | + found checking which position in the array has content allows us to figure | |
| 1176 | + out which of the original regexes / match groups triggered the match. | |
| 1177 | + | |
| 1178 | + The match object itself (the result of `Regex.exec`) is returned but also | |
| 1179 | + enhanced by merging in any meta-data that was registered with the regex. | |
| 1180 | + This is how we keep track of which mode matched, and what type of rule | |
| 1181 | + (`illegal`, `begin`, end, etc). | |
| 1182 | + */ | |
| 1183 | + class MultiRegex { | |
| 1184 | + constructor() { | |
| 1185 | + this.matchIndexes = {}; | |
| 1186 | + // @ts-ignore | |
| 1187 | + this.regexes = []; | |
| 1188 | + this.matchAt = 1; | |
| 1189 | + this.position = 0; | |
| 1190 | + } | |
| 1191 | + | |
| 1192 | + // @ts-ignore | |
| 1193 | + addRule(re, opts) { | |
| 1194 | + opts.position = this.position++; | |
| 1195 | + // @ts-ignore | |
| 1196 | + this.matchIndexes[this.matchAt] = opts; | |
| 1197 | + this.regexes.push([opts, re]); | |
| 1198 | + this.matchAt += countMatchGroups(re) + 1; | |
| 1199 | + } | |
| 1200 | + | |
| 1201 | + compile() { | |
| 1202 | + if (this.regexes.length === 0) { | |
| 1203 | + // avoids the need to check length every time exec is called | |
| 1204 | + // @ts-ignore | |
| 1205 | + this.exec = () => null; | |
| 1206 | + } | |
| 1207 | + const terminators = this.regexes.map(el => el[1]); | |
| 1208 | + this.matcherRe = langRe(_rewriteBackreferences(terminators, { joinWith: '|' }), true); | |
| 1209 | + this.lastIndex = 0; | |
| 1210 | + } | |
| 1211 | + | |
| 1212 | + /** @param {string} s */ | |
| 1213 | + exec(s) { | |
| 1214 | + this.matcherRe.lastIndex = this.lastIndex; | |
| 1215 | + const match = this.matcherRe.exec(s); | |
| 1216 | + if (!match) { return null; } | |
| 1217 | + | |
| 1218 | + // eslint-disable-next-line no-undefined | |
| 1219 | + const i = match.findIndex((el, i) => i > 0 && el !== undefined); | |
| 1220 | + // @ts-ignore | |
| 1221 | + const matchData = this.matchIndexes[i]; | |
| 1222 | + // trim off any earlier non-relevant match groups (ie, the other regex | |
| 1223 | + // match groups that make up the multi-matcher) | |
| 1224 | + match.splice(0, i); | |
| 1225 | + | |
| 1226 | + return Object.assign(match, matchData); | |
| 1227 | + } | |
| 1228 | + } | |
| 1229 | + | |
| 1230 | + /* | |
| 1231 | + Created to solve the key deficiently with MultiRegex - there is no way to | |
| 1232 | + test for multiple matches at a single location. Why would we need to do | |
| 1233 | + that? In the future a more dynamic engine will allow certain matches to be | |
| 1234 | + ignored. An example: if we matched say the 3rd regex in a large group but | |
| 1235 | + decided to ignore it - we'd need to started testing again at the 4th | |
| 1236 | + regex... but MultiRegex itself gives us no real way to do that. | |
| 1237 | + | |
| 1238 | + So what this class creates MultiRegexs on the fly for whatever search | |
| 1239 | + position they are needed. | |
| 1240 | + | |
| 1241 | + NOTE: These additional MultiRegex objects are created dynamically. For most | |
| 1242 | + grammars most of the time we will never actually need anything more than the | |
| 1243 | + first MultiRegex - so this shouldn't have too much overhead. | |
| 1244 | + | |
| 1245 | + Say this is our search group, and we match regex3, but wish to ignore it. | |
| 1246 | + | |
| 1247 | + regex1 | regex2 | regex3 | regex4 | regex5 ' ie, startAt = 0 | |
| 1248 | + | |
| 1249 | + What we need is a new MultiRegex that only includes the remaining | |
| 1250 | + possibilities: | |
| 1251 | + | |
| 1252 | + regex4 | regex5 ' ie, startAt = 3 | |
| 1253 | + | |
| 1254 | + This class wraps all that complexity up in a simple API... `startAt` decides | |
| 1255 | + where in the array of expressions to start doing the matching. It | |
| 1256 | + auto-increments, so if a match is found at position 2, then startAt will be | |
| 1257 | + set to 3. If the end is reached startAt will return to 0. | |
| 1258 | + | |
| 1259 | + MOST of the time the parser will be setting startAt manually to 0. | |
| 1260 | + */ | |
| 1261 | + class ResumableMultiRegex { | |
| 1262 | + constructor() { | |
| 1263 | + // @ts-ignore | |
| 1264 | + this.rules = []; | |
| 1265 | + // @ts-ignore | |
| 1266 | + this.multiRegexes = []; | |
| 1267 | + this.count = 0; | |
| 1268 | + | |
| 1269 | + this.lastIndex = 0; | |
| 1270 | + this.regexIndex = 0; | |
| 1271 | + } | |
| 1272 | + | |
| 1273 | + // @ts-ignore | |
| 1274 | + getMatcher(index) { | |
| 1275 | + if (this.multiRegexes[index]) return this.multiRegexes[index]; | |
| 1276 | + | |
| 1277 | + const matcher = new MultiRegex(); | |
| 1278 | + this.rules.slice(index).forEach(([re, opts]) => matcher.addRule(re, opts)); | |
| 1279 | + matcher.compile(); | |
| 1280 | + this.multiRegexes[index] = matcher; | |
| 1281 | + return matcher; | |
| 1282 | + } | |
| 1283 | + | |
| 1284 | + resumingScanAtSamePosition() { | |
| 1285 | + return this.regexIndex !== 0; | |
| 1286 | + } | |
| 1287 | + | |
| 1288 | + considerAll() { | |
| 1289 | + this.regexIndex = 0; | |
| 1290 | + } | |
| 1291 | + | |
| 1292 | + // @ts-ignore | |
| 1293 | + addRule(re, opts) { | |
| 1294 | + this.rules.push([re, opts]); | |
| 1295 | + if (opts.type === "begin") this.count++; | |
| 1296 | + } | |
| 1297 | + | |
| 1298 | + /** @param {string} s */ | |
| 1299 | + exec(s) { | |
| 1300 | + const m = this.getMatcher(this.regexIndex); | |
| 1301 | + m.lastIndex = this.lastIndex; | |
| 1302 | + let result = m.exec(s); | |
| 1303 | + | |
| 1304 | + // The following is because we have no easy way to say "resume scanning at the | |
| 1305 | + // existing position but also skip the current rule ONLY". What happens is | |
| 1306 | + // all prior rules are also skipped which can result in matching the wrong | |
| 1307 | + // thing. Example of matching "booger": | |
| 1308 | + | |
| 1309 | + // our matcher is [string, "booger", number] | |
| 1310 | + // | |
| 1311 | + // ....booger.... | |
| 1312 | + | |
| 1313 | + // if "booger" is ignored then we'd really need a regex to scan from the | |
| 1314 | + // SAME position for only: [string, number] but ignoring "booger" (if it | |
| 1315 | + // was the first match), a simple resume would scan ahead who knows how | |
| 1316 | + // far looking only for "number", ignoring potential string matches (or | |
| 1317 | + // future "booger" matches that might be valid.) | |
| 1318 | + | |
| 1319 | + // So what we do: We execute two matchers, one resuming at the same | |
| 1320 | + // position, but the second full matcher starting at the position after: | |
| 1321 | + | |
| 1322 | + // /--- resume first regex match here (for [number]) | |
| 1323 | + // |/---- full match here for [string, "booger", number] | |
| 1324 | + // vv | |
| 1325 | + // ....booger.... | |
| 1326 | + | |
| 1327 | + // Which ever results in a match first is then used. So this 3-4 step | |
| 1328 | + // process essentially allows us to say "match at this position, excluding | |
| 1329 | + // a prior rule that was ignored". | |
| 1330 | + // | |
| 1331 | + // 1. Match "booger" first, ignore. Also proves that [string] does non match. | |
| 1332 | + // 2. Resume matching for [number] | |
| 1333 | + // 3. Match at index + 1 for [string, "booger", number] | |
| 1334 | + // 4. If #2 and #3 result in matches, which came first? | |
| 1335 | + if (this.resumingScanAtSamePosition()) { | |
| 1336 | + if (result && result.index === this.lastIndex) ; else { // use the second matcher result | |
| 1337 | + const m2 = this.getMatcher(0); | |
| 1338 | + m2.lastIndex = this.lastIndex + 1; | |
| 1339 | + result = m2.exec(s); | |
| 1340 | + } | |
| 1341 | + } | |
| 1342 | + | |
| 1343 | + if (result) { | |
| 1344 | + this.regexIndex += result.position + 1; | |
| 1345 | + if (this.regexIndex === this.count) { | |
| 1346 | + // wrap-around to considering all matches again | |
| 1347 | + this.considerAll(); | |
| 1348 | + } | |
| 1349 | + } | |
| 1350 | + | |
| 1351 | + return result; | |
| 1352 | + } | |
| 1353 | + } | |
| 1354 | + | |
| 1355 | + /** | |
| 1356 | + * Given a mode, builds a huge ResumableMultiRegex that can be used to walk | |
| 1357 | + * the content and find matches. | |
| 1358 | + * | |
| 1359 | + * @param {CompiledMode} mode | |
| 1360 | + * @returns {ResumableMultiRegex} | |
| 1361 | + */ | |
| 1362 | + function buildModeRegex(mode) { | |
| 1363 | + const mm = new ResumableMultiRegex(); | |
| 1364 | + | |
| 1365 | + mode.contains.forEach(term => mm.addRule(term.begin, { rule: term, type: "begin" })); | |
| 1366 | + | |
| 1367 | + if (mode.terminatorEnd) { | |
| 1368 | + mm.addRule(mode.terminatorEnd, { type: "end" }); | |
| 1369 | + } | |
| 1370 | + if (mode.illegal) { | |
| 1371 | + mm.addRule(mode.illegal, { type: "illegal" }); | |
| 1372 | + } | |
| 1373 | + | |
| 1374 | + return mm; | |
| 1375 | + } | |
| 1376 | + | |
| 1377 | + /** skip vs abort vs ignore | |
| 1378 | + * | |
| 1379 | + * @skip - The mode is still entered and exited normally (and contains rules apply), | |
| 1380 | + * but all content is held and added to the parent buffer rather than being | |
| 1381 | + * output when the mode ends. Mostly used with `sublanguage` to build up | |
| 1382 | + * a single large buffer than can be parsed by sublanguage. | |
| 1383 | + * | |
| 1384 | + * - The mode begin ands ends normally. | |
| 1385 | + * - Content matched is added to the parent mode buffer. | |
| 1386 | + * - The parser cursor is moved forward normally. | |
| 1387 | + * | |
| 1388 | + * @abort - A hack placeholder until we have ignore. Aborts the mode (as if it | |
| 1389 | + * never matched) but DOES NOT continue to match subsequent `contains` | |
| 1390 | + * modes. Abort is bad/suboptimal because it can result in modes | |
| 1391 | + * farther down not getting applied because an earlier rule eats the | |
| 1392 | + * content but then aborts. | |
| 1393 | + * | |
| 1394 | + * - The mode does not begin. | |
| 1395 | + * - Content matched by `begin` is added to the mode buffer. | |
| 1396 | + * - The parser cursor is moved forward accordingly. | |
| 1397 | + * | |
| 1398 | + * @ignore - Ignores the mode (as if it never matched) and continues to match any | |
| 1399 | + * subsequent `contains` modes. Ignore isn't technically possible with | |
| 1400 | + * the current parser implementation. | |
| 1401 | + * | |
| 1402 | + * - The mode does not begin. | |
| 1403 | + * - Content matched by `begin` is ignored. | |
| 1404 | + * - The parser cursor is not moved forward. | |
| 1405 | + */ | |
| 1406 | + | |
| 1407 | + /** | |
| 1408 | + * Compiles an individual mode | |
| 1409 | + * | |
| 1410 | + * This can raise an error if the mode contains certain detectable known logic | |
| 1411 | + * issues. | |
| 1412 | + * @param {Mode} mode | |
| 1413 | + * @param {CompiledMode | null} [parent] | |
| 1414 | + * @returns {CompiledMode | never} | |
| 1415 | + */ | |
| 1416 | + function compileMode(mode, parent) { | |
| 1417 | + const cmode = /** @type CompiledMode */ (mode); | |
| 1418 | + if (mode.isCompiled) return cmode; | |
| 1419 | + | |
| 1420 | + [ | |
| 1421 | + scopeClassName, | |
| 1422 | + // do this early so compiler extensions generally don't have to worry about | |
| 1423 | + // the distinction between match/begin | |
| 1424 | + compileMatch, | |
| 1425 | + MultiClass, | |
| 1426 | + beforeMatchExt | |
| 1427 | + ].forEach(ext => ext(mode, parent)); | |
| 1428 | + | |
| 1429 | + language.compilerExtensions.forEach(ext => ext(mode, parent)); | |
| 1430 | + | |
| 1431 | + // __beforeBegin is considered private API, internal use only | |
| 1432 | + mode.__beforeBegin = null; | |
| 1433 | + | |
| 1434 | + [ | |
| 1435 | + beginKeywords, | |
| 1436 | + // do this later so compiler extensions that come earlier have access to the | |
| 1437 | + // raw array if they wanted to perhaps manipulate it, etc. | |
| 1438 | + compileIllegal, | |
| 1439 | + // default to 1 relevance if not specified | |
| 1440 | + compileRelevance | |
| 1441 | + ].forEach(ext => ext(mode, parent)); | |
| 1442 | + | |
| 1443 | + mode.isCompiled = true; | |
| 1444 | + | |
| 1445 | + let keywordPattern = null; | |
| 1446 | + if (typeof mode.keywords === "object" && mode.keywords.$pattern) { | |
| 1447 | + // we need a copy because keywords might be compiled multiple times | |
| 1448 | + // so we can't go deleting $pattern from the original on the first | |
| 1449 | + // pass | |
| 1450 | + mode.keywords = Object.assign({}, mode.keywords); | |
| 1451 | + keywordPattern = mode.keywords.$pattern; | |
| 1452 | + delete mode.keywords.$pattern; | |
| 1453 | + } | |
| 1454 | + keywordPattern = keywordPattern || /\w+/; | |
| 1455 | + | |
| 1456 | + if (mode.keywords) { | |
| 1457 | + mode.keywords = compileKeywords(mode.keywords, language.case_insensitive); | |
| 1458 | + } | |
| 1459 | + | |
| 1460 | + cmode.keywordPatternRe = langRe(keywordPattern, true); | |
| 1461 | + | |
| 1462 | + if (parent) { | |
| 1463 | + if (!mode.begin) mode.begin = /\B|\b/; | |
| 1464 | + cmode.beginRe = langRe(cmode.begin); | |
| 1465 | + if (!mode.end && !mode.endsWithParent) mode.end = /\B|\b/; | |
| 1466 | + if (mode.end) cmode.endRe = langRe(cmode.end); | |
| 1467 | + cmode.terminatorEnd = source(cmode.end) || ''; | |
| 1468 | + if (mode.endsWithParent && parent.terminatorEnd) { | |
| 1469 | + cmode.terminatorEnd += (mode.end ? '|' : '') + parent.terminatorEnd; | |
| 1470 | + } | |
| 1471 | + } | |
| 1472 | + if (mode.illegal) cmode.illegalRe = langRe(/** @type {RegExp | string} */ (mode.illegal)); | |
| 1473 | + if (!mode.contains) mode.contains = []; | |
| 1474 | + | |
| 1475 | + mode.contains = [].concat(...mode.contains.map(function(c) { | |
| 1476 | + return expandOrCloneMode(c === 'self' ? mode : c); | |
| 1477 | + })); | |
| 1478 | + mode.contains.forEach(function(c) { compileMode(/** @type Mode */ (c), cmode); }); | |
| 1479 | + | |
| 1480 | + if (mode.starts) { | |
| 1481 | + compileMode(mode.starts, parent); | |
| 1482 | + } | |
| 1483 | + | |
| 1484 | + cmode.matcher = buildModeRegex(cmode); | |
| 1485 | + return cmode; | |
| 1486 | + } | |
| 1487 | + | |
| 1488 | + if (!language.compilerExtensions) language.compilerExtensions = []; | |
| 1489 | + | |
| 1490 | + // self is not valid at the top-level | |
| 1491 | + if (language.contains && language.contains.includes('self')) { | |
| 1492 | + throw new Error("ERR: contains `self` is not supported at the top-level of a language. See documentation."); | |
| 1493 | + } | |
| 1494 | + | |
| 1495 | + // we need a null object, which inherit will guarantee | |
| 1496 | + language.classNameAliases = inherit$1(language.classNameAliases || {}); | |
| 1497 | + | |
| 1498 | + return compileMode(/** @type Mode */ (language)); | |
| 1499 | +} | |
| 1500 | + | |
| 1501 | +/** | |
| 1502 | + * Determines if a mode has a dependency on it's parent or not | |
| 1503 | + * | |
| 1504 | + * If a mode does have a parent dependency then often we need to clone it if | |
| 1505 | + * it's used in multiple places so that each copy points to the correct parent, | |
| 1506 | + * where-as modes without a parent can often safely be re-used at the bottom of | |
| 1507 | + * a mode chain. | |
| 1508 | + * | |
| 1509 | + * @param {Mode | null} mode | |
| 1510 | + * @returns {boolean} - is there a dependency on the parent? | |
| 1511 | + * */ | |
| 1512 | +function dependencyOnParent(mode) { | |
| 1513 | + if (!mode) return false; | |
| 1514 | + | |
| 1515 | + return mode.endsWithParent || dependencyOnParent(mode.starts); | |
| 1516 | +} | |
| 1517 | + | |
| 1518 | +/** | |
| 1519 | + * Expands a mode or clones it if necessary | |
| 1520 | + * | |
| 1521 | + * This is necessary for modes with parental dependenceis (see notes on | |
| 1522 | + * `dependencyOnParent`) and for nodes that have `variants` - which must then be | |
| 1523 | + * exploded into their own individual modes at compile time. | |
| 1524 | + * | |
| 1525 | + * @param {Mode} mode | |
| 1526 | + * @returns {Mode | Mode[]} | |
| 1527 | + * */ | |
| 1528 | +function expandOrCloneMode(mode) { | |
| 1529 | + if (mode.variants && !mode.cachedVariants) { | |
| 1530 | + mode.cachedVariants = mode.variants.map(function(variant) { | |
| 1531 | + return inherit$1(mode, { variants: null }, variant); | |
| 1532 | + }); | |
| 1533 | + } | |
| 1534 | + | |
| 1535 | + // EXPAND | |
| 1536 | + // if we have variants then essentially "replace" the mode with the variants | |
| 1537 | + // this happens in compileMode, where this function is called from | |
| 1538 | + if (mode.cachedVariants) { | |
| 1539 | + return mode.cachedVariants; | |
| 1540 | + } | |
| 1541 | + | |
| 1542 | + // CLONE | |
| 1543 | + // if we have dependencies on parents then we need a unique | |
| 1544 | + // instance of ourselves, so we can be reused with many | |
| 1545 | + // different parents without issue | |
| 1546 | + if (dependencyOnParent(mode)) { | |
| 1547 | + return inherit$1(mode, { starts: mode.starts ? inherit$1(mode.starts) : null }); | |
| 1548 | + } | |
| 1549 | + | |
| 1550 | + if (Object.isFrozen(mode)) { | |
| 1551 | + return inherit$1(mode); | |
| 1552 | + } | |
| 1553 | + | |
| 1554 | + // no special dependency issues, just return ourselves | |
| 1555 | + return mode; | |
| 1556 | +} | |
| 1557 | + | |
| 1558 | +var version = "11.11.1"; | |
| 1559 | + | |
| 1560 | +class HTMLInjectionError extends Error { | |
| 1561 | + constructor(reason, html) { | |
| 1562 | + super(reason); | |
| 1563 | + this.name = "HTMLInjectionError"; | |
| 1564 | + this.html = html; | |
| 1565 | + } | |
| 1566 | +} | |
| 1567 | + | |
| 1568 | +/* | |
| 1569 | +Syntax highlighting with language autodetection. | |
| 1570 | +https://highlightjs.org/ | |
| 1571 | +*/ | |
| 1572 | + | |
| 1573 | + | |
| 1574 | + | |
| 1575 | +/** | |
| 1576 | +@typedef {import('highlight.js').Mode} Mode | |
| 1577 | +@typedef {import('highlight.js').CompiledMode} CompiledMode | |
| 1578 | +@typedef {import('highlight.js').CompiledScope} CompiledScope | |
| 1579 | +@typedef {import('highlight.js').Language} Language | |
| 1580 | +@typedef {import('highlight.js').HLJSApi} HLJSApi | |
| 1581 | +@typedef {import('highlight.js').HLJSPlugin} HLJSPlugin | |
| 1582 | +@typedef {import('highlight.js').PluginEvent} PluginEvent | |
| 1583 | +@typedef {import('highlight.js').HLJSOptions} HLJSOptions | |
| 1584 | +@typedef {import('highlight.js').LanguageFn} LanguageFn | |
| 1585 | +@typedef {import('highlight.js').HighlightedHTMLElement} HighlightedHTMLElement | |
| 1586 | +@typedef {import('highlight.js').BeforeHighlightContext} BeforeHighlightContext | |
| 1587 | +@typedef {import('highlight.js/private').MatchType} MatchType | |
| 1588 | +@typedef {import('highlight.js/private').KeywordData} KeywordData | |
| 1589 | +@typedef {import('highlight.js/private').EnhancedMatch} EnhancedMatch | |
| 1590 | +@typedef {import('highlight.js/private').AnnotatedError} AnnotatedError | |
| 1591 | +@typedef {import('highlight.js').AutoHighlightResult} AutoHighlightResult | |
| 1592 | +@typedef {import('highlight.js').HighlightOptions} HighlightOptions | |
| 1593 | +@typedef {import('highlight.js').HighlightResult} HighlightResult | |
| 1594 | +*/ | |
| 1595 | + | |
| 1596 | + | |
| 1597 | +const escape = escapeHTML; | |
| 1598 | +const inherit = inherit$1; | |
| 1599 | +const NO_MATCH = Symbol("nomatch"); | |
| 1600 | +const MAX_KEYWORD_HITS = 7; | |
| 1601 | + | |
| 1602 | +/** | |
| 1603 | + * @param {any} hljs - object that is extended (legacy) | |
| 1604 | + * @returns {HLJSApi} | |
| 1605 | + */ | |
| 1606 | +const HLJS = function(hljs) { | |
| 1607 | + // Global internal variables used within the highlight.js library. | |
| 1608 | + /** @type {Record<string, Language>} */ | |
| 1609 | + const languages = Object.create(null); | |
| 1610 | + /** @type {Record<string, string>} */ | |
| 1611 | + const aliases = Object.create(null); | |
| 1612 | + /** @type {HLJSPlugin[]} */ | |
| 1613 | + const plugins = []; | |
| 1614 | + | |
| 1615 | + // safe/production mode - swallows more errors, tries to keep running | |
| 1616 | + // even if a single syntax or parse hits a fatal error | |
| 1617 | + let SAFE_MODE = true; | |
| 1618 | + const LANGUAGE_NOT_FOUND = "Could not find the language '{}', did you forget to load/include a language module?"; | |
| 1619 | + /** @type {Language} */ | |
| 1620 | + const PLAINTEXT_LANGUAGE = { disableAutodetect: true, name: 'Plain text', contains: [] }; | |
| 1621 | + | |
| 1622 | + // Global options used when within external APIs. This is modified when | |
| 1623 | + // calling the `hljs.configure` function. | |
| 1624 | + /** @type HLJSOptions */ | |
| 1625 | + let options = { | |
| 1626 | + ignoreUnescapedHTML: false, | |
| 1627 | + throwUnescapedHTML: false, | |
| 1628 | + noHighlightRe: /^(no-?highlight)$/i, | |
| 1629 | + languageDetectRe: /\blang(?:uage)?-([\w-]+)\b/i, | |
| 1630 | + classPrefix: 'hljs-', | |
| 1631 | + cssSelector: 'pre code', | |
| 1632 | + languages: null, | |
| 1633 | + // beta configuration options, subject to change, welcome to discuss | |
| 1634 | + // https://github.com/highlightjs/highlight.js/issues/1086 | |
| 1635 | + __emitter: TokenTreeEmitter | |
| 1636 | + }; | |
| 1637 | + | |
| 1638 | + /* Utility functions */ | |
| 1639 | + | |
| 1640 | + /** | |
| 1641 | + * Tests a language name to see if highlighting should be skipped | |
| 1642 | + * @param {string} languageName | |
| 1643 | + */ | |
| 1644 | + function shouldNotHighlight(languageName) { | |
| 1645 | + return options.noHighlightRe.test(languageName); | |
| 1646 | + } | |
| 1647 | + | |
| 1648 | + /** | |
| 1649 | + * @param {HighlightedHTMLElement} block - the HTML element to determine language for | |
| 1650 | + */ | |
| 1651 | + function blockLanguage(block) { | |
| 1652 | + let classes = block.className + ' '; | |
| 1653 | + | |
| 1654 | + classes += block.parentNode ? block.parentNode.className : ''; | |
| 1655 | + | |
| 1656 | + // language-* takes precedence over non-prefixed class names. | |
| 1657 | + const match = options.languageDetectRe.exec(classes); | |
| 1658 | + if (match) { | |
| 1659 | + const language = getLanguage(match[1]); | |
| 1660 | + if (!language) { | |
| 1661 | + warn(LANGUAGE_NOT_FOUND.replace("{}", match[1])); | |
| 1662 | + warn("Falling back to no-highlight mode for this block.", block); | |
| 1663 | + } | |
| 1664 | + return language ? match[1] : 'no-highlight'; | |
| 1665 | + } | |
| 1666 | + | |
| 1667 | + return classes | |
| 1668 | + .split(/\s+/) | |
| 1669 | + .find((_class) => shouldNotHighlight(_class) || getLanguage(_class)); | |
| 1670 | + } | |
| 1671 | + | |
| 1672 | + /** | |
| 1673 | + * Core highlighting function. | |
| 1674 | + * | |
| 1675 | + * OLD API | |
| 1676 | + * highlight(lang, code, ignoreIllegals, continuation) | |
| 1677 | + * | |
| 1678 | + * NEW API | |
| 1679 | + * highlight(code, {lang, ignoreIllegals}) | |
| 1680 | + * | |
| 1681 | + * @param {string} codeOrLanguageName - the language to use for highlighting | |
| 1682 | + * @param {string | HighlightOptions} optionsOrCode - the code to highlight | |
| 1683 | + * @param {boolean} [ignoreIllegals] - whether to ignore illegal matches, default is to bail | |
| 1684 | + * | |
| 1685 | + * @returns {HighlightResult} Result - an object that represents the result | |
| 1686 | + * @property {string} language - the language name | |
| 1687 | + * @property {number} relevance - the relevance score | |
| 1688 | + * @property {string} value - the highlighted HTML code | |
| 1689 | + * @property {string} code - the original raw code | |
| 1690 | + * @property {CompiledMode} top - top of the current mode stack | |
| 1691 | + * @property {boolean} illegal - indicates whether any illegal matches were found | |
| 1692 | + */ | |
| 1693 | + function highlight(codeOrLanguageName, optionsOrCode, ignoreIllegals) { | |
| 1694 | + let code = ""; | |
| 1695 | + let languageName = ""; | |
| 1696 | + if (typeof optionsOrCode === "object") { | |
| 1697 | + code = codeOrLanguageName; | |
| 1698 | + ignoreIllegals = optionsOrCode.ignoreIllegals; | |
| 1699 | + languageName = optionsOrCode.language; | |
| 1700 | + } else { | |
| 1701 | + // old API | |
| 1702 | + deprecated("10.7.0", "highlight(lang, code, ...args) has been deprecated."); | |
| 1703 | + deprecated("10.7.0", "Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"); | |
| 1704 | + languageName = codeOrLanguageName; | |
| 1705 | + code = optionsOrCode; | |
| 1706 | + } | |
| 1707 | + | |
| 1708 | + // https://github.com/highlightjs/highlight.js/issues/3149 | |
| 1709 | + // eslint-disable-next-line no-undefined | |
| 1710 | + if (ignoreIllegals === undefined) { ignoreIllegals = true; } | |
| 1711 | + | |
| 1712 | + /** @type {BeforeHighlightContext} */ | |
| 1713 | + const context = { | |
| 1714 | + code, | |
| 1715 | + language: languageName | |
| 1716 | + }; | |
| 1717 | + // the plugin can change the desired language or the code to be highlighted | |
| 1718 | + // just be changing the object it was passed | |
| 1719 | + fire("before:highlight", context); | |
| 1720 | + | |
| 1721 | + // a before plugin can usurp the result completely by providing it's own | |
| 1722 | + // in which case we don't even need to call highlight | |
| 1723 | + const result = context.result | |
| 1724 | + ? context.result | |
| 1725 | + : _highlight(context.language, context.code, ignoreIllegals); | |
| 1726 | + | |
| 1727 | + result.code = context.code; | |
| 1728 | + // the plugin can change anything in result to suite it | |
| 1729 | + fire("after:highlight", result); | |
| 1730 | + | |
| 1731 | + return result; | |
| 1732 | + } | |
| 1733 | + | |
| 1734 | + /** | |
| 1735 | + * private highlight that's used internally and does not fire callbacks | |
| 1736 | + * | |
| 1737 | + * @param {string} languageName - the language to use for highlighting | |
| 1738 | + * @param {string} codeToHighlight - the code to highlight | |
| 1739 | + * @param {boolean?} [ignoreIllegals] - whether to ignore illegal matches, default is to bail | |
| 1740 | + * @param {CompiledMode?} [continuation] - current continuation mode, if any | |
| 1741 | + * @returns {HighlightResult} - result of the highlight operation | |
| 1742 | + */ | |
| 1743 | + function _highlight(languageName, codeToHighlight, ignoreIllegals, continuation) { | |
| 1744 | + const keywordHits = Object.create(null); | |
| 1745 | + | |
| 1746 | + /** | |
| 1747 | + * Return keyword data if a match is a keyword | |
| 1748 | + * @param {CompiledMode} mode - current mode | |
| 1749 | + * @param {string} matchText - the textual match | |
| 1750 | + * @returns {KeywordData | false} | |
| 1751 | + */ | |
| 1752 | + function keywordData(mode, matchText) { | |
| 1753 | + return mode.keywords[matchText]; | |
| 1754 | + } | |
| 1755 | + | |
| 1756 | + function processKeywords() { | |
| 1757 | + if (!top.keywords) { | |
| 1758 | + emitter.addText(modeBuffer); | |
| 1759 | + return; | |
| 1760 | + } | |
| 1761 | + | |
| 1762 | + let lastIndex = 0; | |
| 1763 | + top.keywordPatternRe.lastIndex = 0; | |
| 1764 | + let match = top.keywordPatternRe.exec(modeBuffer); | |
| 1765 | + let buf = ""; | |
| 1766 | + | |
| 1767 | + while (match) { | |
| 1768 | + buf += modeBuffer.substring(lastIndex, match.index); | |
| 1769 | + const word = language.case_insensitive ? match[0].toLowerCase() : match[0]; | |
| 1770 | + const data = keywordData(top, word); | |
| 1771 | + if (data) { | |
| 1772 | + const [kind, keywordRelevance] = data; | |
| 1773 | + emitter.addText(buf); | |
| 1774 | + buf = ""; | |
| 1775 | + | |
| 1776 | + keywordHits[word] = (keywordHits[word] || 0) + 1; | |
| 1777 | + if (keywordHits[word] <= MAX_KEYWORD_HITS) relevance += keywordRelevance; | |
| 1778 | + if (kind.startsWith("_")) { | |
| 1779 | + // _ implied for relevance only, do not highlight | |
| 1780 | + // by applying a class name | |
| 1781 | + buf += match[0]; | |
| 1782 | + } else { | |
| 1783 | + const cssClass = language.classNameAliases[kind] || kind; | |
| 1784 | + emitKeyword(match[0], cssClass); | |
| 1785 | + } | |
| 1786 | + } else { | |
| 1787 | + buf += match[0]; | |
| 1788 | + } | |
| 1789 | + lastIndex = top.keywordPatternRe.lastIndex; | |
| 1790 | + match = top.keywordPatternRe.exec(modeBuffer); | |
| 1791 | + } | |
| 1792 | + buf += modeBuffer.substring(lastIndex); | |
| 1793 | + emitter.addText(buf); | |
| 1794 | + } | |
| 1795 | + | |
| 1796 | + function processSubLanguage() { | |
| 1797 | + if (modeBuffer === "") return; | |
| 1798 | + /** @type HighlightResult */ | |
| 1799 | + let result = null; | |
| 1800 | + | |
| 1801 | + if (typeof top.subLanguage === 'string') { | |
| 1802 | + if (!languages[top.subLanguage]) { | |
| 1803 | + emitter.addText(modeBuffer); | |
| 1804 | + return; | |
| 1805 | + } | |
| 1806 | + result = _highlight(top.subLanguage, modeBuffer, true, continuations[top.subLanguage]); | |
| 1807 | + continuations[top.subLanguage] = /** @type {CompiledMode} */ (result._top); | |
| 1808 | + } else { | |
| 1809 | + result = highlightAuto(modeBuffer, top.subLanguage.length ? top.subLanguage : null); | |
| 1810 | + } | |
| 1811 | + | |
| 1812 | + // Counting embedded language score towards the host language may be disabled | |
| 1813 | + // with zeroing the containing mode relevance. Use case in point is Markdown that | |
| 1814 | + // allows XML everywhere and makes every XML snippet to have a much larger Markdown | |
| 1815 | + // score. | |
| 1816 | + if (top.relevance > 0) { | |
| 1817 | + relevance += result.relevance; | |
| 1818 | + } | |
| 1819 | + emitter.__addSublanguage(result._emitter, result.language); | |
| 1820 | + } | |
| 1821 | + | |
| 1822 | + function processBuffer() { | |
| 1823 | + if (top.subLanguage != null) { | |
| 1824 | + processSubLanguage(); | |
| 1825 | + } else { | |
| 1826 | + processKeywords(); | |
| 1827 | + } | |
| 1828 | + modeBuffer = ''; | |
| 1829 | + } | |
| 1830 | + | |
| 1831 | + /** | |
| 1832 | + * @param {string} text | |
| 1833 | + * @param {string} scope | |
| 1834 | + */ | |
| 1835 | + function emitKeyword(keyword, scope) { | |
| 1836 | + if (keyword === "") return; | |
| 1837 | + | |
| 1838 | + emitter.startScope(scope); | |
| 1839 | + emitter.addText(keyword); | |
| 1840 | + emitter.endScope(); | |
| 1841 | + } | |
| 1842 | + | |
| 1843 | + /** | |
| 1844 | + * @param {CompiledScope} scope | |
| 1845 | + * @param {RegExpMatchArray} match | |
| 1846 | + */ | |
| 1847 | + function emitMultiClass(scope, match) { | |
| 1848 | + let i = 1; | |
| 1849 | + const max = match.length - 1; | |
| 1850 | + while (i <= max) { | |
| 1851 | + if (!scope._emit[i]) { i++; continue; } | |
| 1852 | + const klass = language.classNameAliases[scope[i]] || scope[i]; | |
| 1853 | + const text = match[i]; | |
| 1854 | + if (klass) { | |
| 1855 | + emitKeyword(text, klass); | |
| 1856 | + } else { | |
| 1857 | + modeBuffer = text; | |
| 1858 | + processKeywords(); | |
| 1859 | + modeBuffer = ""; | |
| 1860 | + } | |
| 1861 | + i++; | |
| 1862 | + } | |
| 1863 | + } | |
| 1864 | + | |
| 1865 | + /** | |
| 1866 | + * @param {CompiledMode} mode - new mode to start | |
| 1867 | + * @param {RegExpMatchArray} match | |
| 1868 | + */ | |
| 1869 | + function startNewMode(mode, match) { | |
| 1870 | + if (mode.scope && typeof mode.scope === "string") { | |
| 1871 | + emitter.openNode(language.classNameAliases[mode.scope] || mode.scope); | |
| 1872 | + } | |
| 1873 | + if (mode.beginScope) { | |
| 1874 | + // beginScope just wraps the begin match itself in a scope | |
| 1875 | + if (mode.beginScope._wrap) { | |
| 1876 | + emitKeyword(modeBuffer, language.classNameAliases[mode.beginScope._wrap] || mode.beginScope._wrap); | |
| 1877 | + modeBuffer = ""; | |
| 1878 | + } else if (mode.beginScope._multi) { | |
| 1879 | + // at this point modeBuffer should just be the match | |
| 1880 | + emitMultiClass(mode.beginScope, match); | |
| 1881 | + modeBuffer = ""; | |
| 1882 | + } | |
| 1883 | + } | |
| 1884 | + | |
| 1885 | + top = Object.create(mode, { parent: { value: top } }); | |
| 1886 | + return top; | |
| 1887 | + } | |
| 1888 | + | |
| 1889 | + /** | |
| 1890 | + * @param {CompiledMode } mode - the mode to potentially end | |
| 1891 | + * @param {RegExpMatchArray} match - the latest match | |
| 1892 | + * @param {string} matchPlusRemainder - match plus remainder of content | |
| 1893 | + * @returns {CompiledMode | void} - the next mode, or if void continue on in current mode | |
| 1894 | + */ | |
| 1895 | + function endOfMode(mode, match, matchPlusRemainder) { | |
| 1896 | + let matched = startsWith(mode.endRe, matchPlusRemainder); | |
| 1897 | + | |
| 1898 | + if (matched) { | |
| 1899 | + if (mode["on:end"]) { | |
| 1900 | + const resp = new Response(mode); | |
| 1901 | + mode["on:end"](match, resp); | |
| 1902 | + if (resp.isMatchIgnored) matched = false; | |
| 1903 | + } | |
| 1904 | + | |
| 1905 | + if (matched) { | |
| 1906 | + while (mode.endsParent && mode.parent) { | |
| 1907 | + mode = mode.parent; | |
| 1908 | + } | |
| 1909 | + return mode; | |
| 1910 | + } | |
| 1911 | + } | |
| 1912 | + // even if on:end fires an `ignore` it's still possible | |
| 1913 | + // that we might trigger the end node because of a parent mode | |
| 1914 | + if (mode.endsWithParent) { | |
| 1915 | + return endOfMode(mode.parent, match, matchPlusRemainder); | |
| 1916 | + } | |
| 1917 | + } | |
| 1918 | + | |
| 1919 | + /** | |
| 1920 | + * Handle matching but then ignoring a sequence of text | |
| 1921 | + * | |
| 1922 | + * @param {string} lexeme - string containing full match text | |
| 1923 | + */ | |
| 1924 | + function doIgnore(lexeme) { | |
| 1925 | + if (top.matcher.regexIndex === 0) { | |
| 1926 | + // no more regexes to potentially match here, so we move the cursor forward one | |
| 1927 | + // space | |
| 1928 | + modeBuffer += lexeme[0]; | |
| 1929 | + return 1; | |
| 1930 | + } else { | |
| 1931 | + // no need to move the cursor, we still have additional regexes to try and | |
| 1932 | + // match at this very spot | |
| 1933 | + resumeScanAtSamePosition = true; | |
| 1934 | + return 0; | |
| 1935 | + } | |
| 1936 | + } | |
| 1937 | + | |
| 1938 | + /** | |
| 1939 | + * Handle the start of a new potential mode match | |
| 1940 | + * | |
| 1941 | + * @param {EnhancedMatch} match - the current match | |
| 1942 | + * @returns {number} how far to advance the parse cursor | |
| 1943 | + */ | |
| 1944 | + function doBeginMatch(match) { | |
| 1945 | + const lexeme = match[0]; | |
| 1946 | + const newMode = match.rule; | |
| 1947 | + | |
| 1948 | + const resp = new Response(newMode); | |
| 1949 | + // first internal before callbacks, then the public ones | |
| 1950 | + const beforeCallbacks = [newMode.__beforeBegin, newMode["on:begin"]]; | |
| 1951 | + for (const cb of beforeCallbacks) { | |
| 1952 | + if (!cb) continue; | |
| 1953 | + cb(match, resp); | |
| 1954 | + if (resp.isMatchIgnored) return doIgnore(lexeme); | |
| 1955 | + } | |
| 1956 | + | |
| 1957 | + if (newMode.skip) { | |
| 1958 | + modeBuffer += lexeme; | |
| 1959 | + } else { | |
| 1960 | + if (newMode.excludeBegin) { | |
| 1961 | + modeBuffer += lexeme; | |
| 1962 | + } | |
| 1963 | + processBuffer(); | |
| 1964 | + if (!newMode.returnBegin && !newMode.excludeBegin) { | |
| 1965 | + modeBuffer = lexeme; | |
| 1966 | + } | |
| 1967 | + } | |
| 1968 | + startNewMode(newMode, match); | |
| 1969 | + return newMode.returnBegin ? 0 : lexeme.length; | |
| 1970 | + } | |
| 1971 | + | |
| 1972 | + /** | |
| 1973 | + * Handle the potential end of mode | |
| 1974 | + * | |
| 1975 | + * @param {RegExpMatchArray} match - the current match | |
| 1976 | + */ | |
| 1977 | + function doEndMatch(match) { | |
| 1978 | + const lexeme = match[0]; | |
| 1979 | + const matchPlusRemainder = codeToHighlight.substring(match.index); | |
| 1980 | + | |
| 1981 | + const endMode = endOfMode(top, match, matchPlusRemainder); | |
| 1982 | + if (!endMode) { return NO_MATCH; } | |
| 1983 | + | |
| 1984 | + const origin = top; | |
| 1985 | + if (top.endScope && top.endScope._wrap) { | |
| 1986 | + processBuffer(); | |
| 1987 | + emitKeyword(lexeme, top.endScope._wrap); | |
| 1988 | + } else if (top.endScope && top.endScope._multi) { | |
| 1989 | + processBuffer(); | |
| 1990 | + emitMultiClass(top.endScope, match); | |
| 1991 | + } else if (origin.skip) { | |
| 1992 | + modeBuffer += lexeme; | |
| 1993 | + } else { | |
| 1994 | + if (!(origin.returnEnd || origin.excludeEnd)) { | |
| 1995 | + modeBuffer += lexeme; | |
| 1996 | + } | |
| 1997 | + processBuffer(); | |
| 1998 | + if (origin.excludeEnd) { | |
| 1999 | + modeBuffer = lexeme; | |
| 2000 | + } | |
| 2001 | + } | |
| 2002 | + do { | |
| 2003 | + if (top.scope) { | |
| 2004 | + emitter.closeNode(); | |
| 2005 | + } | |
| 2006 | + if (!top.skip && !top.subLanguage) { | |
| 2007 | + relevance += top.relevance; | |
| 2008 | + } | |
| 2009 | + top = top.parent; | |
| 2010 | + } while (top !== endMode.parent); | |
| 2011 | + if (endMode.starts) { | |
| 2012 | + startNewMode(endMode.starts, match); | |
| 2013 | + } | |
| 2014 | + return origin.returnEnd ? 0 : lexeme.length; | |
| 2015 | + } | |
| 2016 | + | |
| 2017 | + function processContinuations() { | |
| 2018 | + const list = []; | |
| 2019 | + for (let current = top; current !== language; current = current.parent) { | |
| 2020 | + if (current.scope) { | |
| 2021 | + list.unshift(current.scope); | |
| 2022 | + } | |
| 2023 | + } | |
| 2024 | + list.forEach(item => emitter.openNode(item)); | |
| 2025 | + } | |
| 2026 | + | |
| 2027 | + /** @type {{type?: MatchType, index?: number, rule?: Mode}}} */ | |
| 2028 | + let lastMatch = {}; | |
| 2029 | + | |
| 2030 | + /** | |
| 2031 | + * Process an individual match | |
| 2032 | + * | |
| 2033 | + * @param {string} textBeforeMatch - text preceding the match (since the last match) | |
| 2034 | + * @param {EnhancedMatch} [match] - the match itself | |
| 2035 | + */ | |
| 2036 | + function processLexeme(textBeforeMatch, match) { | |
| 2037 | + const lexeme = match && match[0]; | |
| 2038 | + | |
| 2039 | + // add non-matched text to the current mode buffer | |
| 2040 | + modeBuffer += textBeforeMatch; | |
| 2041 | + | |
| 2042 | + if (lexeme == null) { | |
| 2043 | + processBuffer(); | |
| 2044 | + return 0; | |
| 2045 | + } | |
| 2046 | + | |
| 2047 | + // we've found a 0 width match and we're stuck, so we need to advance | |
| 2048 | + // this happens when we have badly behaved rules that have optional matchers to the degree that | |
| 2049 | + // sometimes they can end up matching nothing at all | |
| 2050 | + // Ref: https://github.com/highlightjs/highlight.js/issues/2140 | |
| 2051 | + if (lastMatch.type === "begin" && match.type === "end" && lastMatch.index === match.index && lexeme === "") { | |
| 2052 | + // spit the "skipped" character that our regex choked on back into the output sequence | |
| 2053 | + modeBuffer += codeToHighlight.slice(match.index, match.index + 1); | |
| 2054 | + if (!SAFE_MODE) { | |
| 2055 | + /** @type {AnnotatedError} */ | |
| 2056 | + const err = new Error(`0 width match regex (${languageName})`); | |
| 2057 | + err.languageName = languageName; | |
| 2058 | + err.badRule = lastMatch.rule; | |
| 2059 | + throw err; | |
| 2060 | + } | |
| 2061 | + return 1; | |
| 2062 | + } | |
| 2063 | + lastMatch = match; | |
| 2064 | + | |
| 2065 | + if (match.type === "begin") { | |
| 2066 | + return doBeginMatch(match); | |
| 2067 | + } else if (match.type === "illegal" && !ignoreIllegals) { | |
| 2068 | + // illegal match, we do not continue processing | |
| 2069 | + /** @type {AnnotatedError} */ | |
| 2070 | + const err = new Error('Illegal lexeme "' + lexeme + '" for mode "' + (top.scope || '<unnamed>') + '"'); | |
| 2071 | + err.mode = top; | |
| 2072 | + throw err; | |
| 2073 | + } else if (match.type === "end") { | |
| 2074 | + const processed = doEndMatch(match); | |
| 2075 | + if (processed !== NO_MATCH) { | |
| 2076 | + return processed; | |
| 2077 | + } | |
| 2078 | + } | |
| 2079 | + | |
| 2080 | + // edge case for when illegal matches $ (end of line) which is technically | |
| 2081 | + // a 0 width match but not a begin/end match so it's not caught by the | |
| 2082 | + // first handler (when ignoreIllegals is true) | |
| 2083 | + if (match.type === "illegal" && lexeme === "") { | |
| 2084 | + // advance so we aren't stuck in an infinite loop | |
| 2085 | + modeBuffer += "\n"; | |
| 2086 | + return 1; | |
| 2087 | + } | |
| 2088 | + | |
| 2089 | + // infinite loops are BAD, this is a last ditch catch all. if we have a | |
| 2090 | + // decent number of iterations yet our index (cursor position in our | |
| 2091 | + // parsing) still 3x behind our index then something is very wrong | |
| 2092 | + // so we bail | |
| 2093 | + if (iterations > 100000 && iterations > match.index * 3) { | |
| 2094 | + const err = new Error('potential infinite loop, way more iterations than matches'); | |
| 2095 | + throw err; | |
| 2096 | + } | |
| 2097 | + | |
| 2098 | + /* | |
| 2099 | + Why might be find ourselves here? An potential end match that was | |
| 2100 | + triggered but could not be completed. IE, `doEndMatch` returned NO_MATCH. | |
| 2101 | + (this could be because a callback requests the match be ignored, etc) | |
| 2102 | + | |
| 2103 | + This causes no real harm other than stopping a few times too many. | |
| 2104 | + */ | |
| 2105 | + | |
| 2106 | + modeBuffer += lexeme; | |
| 2107 | + return lexeme.length; | |
| 2108 | + } | |
| 2109 | + | |
| 2110 | + const language = getLanguage(languageName); | |
| 2111 | + if (!language) { | |
| 2112 | + error(LANGUAGE_NOT_FOUND.replace("{}", languageName)); | |
| 2113 | + throw new Error('Unknown language: "' + languageName + '"'); | |
| 2114 | + } | |
| 2115 | + | |
| 2116 | + const md = compileLanguage(language); | |
| 2117 | + let result = ''; | |
| 2118 | + /** @type {CompiledMode} */ | |
| 2119 | + let top = continuation || md; | |
| 2120 | + /** @type Record<string,CompiledMode> */ | |
| 2121 | + const continuations = {}; // keep continuations for sub-languages | |
| 2122 | + const emitter = new options.__emitter(options); | |
| 2123 | + processContinuations(); | |
| 2124 | + let modeBuffer = ''; | |
| 2125 | + let relevance = 0; | |
| 2126 | + let index = 0; | |
| 2127 | + let iterations = 0; | |
| 2128 | + let resumeScanAtSamePosition = false; | |
| 2129 | + | |
| 2130 | + try { | |
| 2131 | + if (!language.__emitTokens) { | |
| 2132 | + top.matcher.considerAll(); | |
| 2133 | + | |
| 2134 | + for (;;) { | |
| 2135 | + iterations++; | |
| 2136 | + if (resumeScanAtSamePosition) { | |
| 2137 | + // only regexes not matched previously will now be | |
| 2138 | + // considered for a potential match | |
| 2139 | + resumeScanAtSamePosition = false; | |
| 2140 | + } else { | |
| 2141 | + top.matcher.considerAll(); | |
| 2142 | + } | |
| 2143 | + top.matcher.lastIndex = index; | |
| 2144 | + | |
| 2145 | + const match = top.matcher.exec(codeToHighlight); | |
| 2146 | + // console.log("match", match[0], match.rule && match.rule.begin) | |
| 2147 | + | |
| 2148 | + if (!match) break; | |
| 2149 | + | |
| 2150 | + const beforeMatch = codeToHighlight.substring(index, match.index); | |
| 2151 | + const processedCount = processLexeme(beforeMatch, match); | |
| 2152 | + index = match.index + processedCount; | |
| 2153 | + } | |
| 2154 | + processLexeme(codeToHighlight.substring(index)); | |
| 2155 | + } else { | |
| 2156 | + language.__emitTokens(codeToHighlight, emitter); | |
| 2157 | + } | |
| 2158 | + | |
| 2159 | + emitter.finalize(); | |
| 2160 | + result = emitter.toHTML(); | |
| 2161 | + | |
| 2162 | + return { | |
| 2163 | + language: languageName, | |
| 2164 | + value: result, | |
| 2165 | + relevance, | |
| 2166 | + illegal: false, | |
| 2167 | + _emitter: emitter, | |
| 2168 | + _top: top | |
| 2169 | + }; | |
| 2170 | + } catch (err) { | |
| 2171 | + if (err.message && err.message.includes('Illegal')) { | |
| 2172 | + return { | |
| 2173 | + language: languageName, | |
| 2174 | + value: escape(codeToHighlight), | |
| 2175 | + illegal: true, | |
| 2176 | + relevance: 0, | |
| 2177 | + _illegalBy: { | |
| 2178 | + message: err.message, | |
| 2179 | + index, | |
| 2180 | + context: codeToHighlight.slice(index - 100, index + 100), | |
| 2181 | + mode: err.mode, | |
| 2182 | + resultSoFar: result | |
| 2183 | + }, | |
| 2184 | + _emitter: emitter | |
| 2185 | + }; | |
| 2186 | + } else if (SAFE_MODE) { | |
| 2187 | + return { | |
| 2188 | + language: languageName, | |
| 2189 | + value: escape(codeToHighlight), | |
| 2190 | + illegal: false, | |
| 2191 | + relevance: 0, | |
| 2192 | + errorRaised: err, | |
| 2193 | + _emitter: emitter, | |
| 2194 | + _top: top | |
| 2195 | + }; | |
| 2196 | + } else { | |
| 2197 | + throw err; | |
| 2198 | + } | |
| 2199 | + } | |
| 2200 | + } | |
| 2201 | + | |
| 2202 | + /** | |
| 2203 | + * returns a valid highlight result, without actually doing any actual work, | |
| 2204 | + * auto highlight starts with this and it's possible for small snippets that | |
| 2205 | + * auto-detection may not find a better match | |
| 2206 | + * @param {string} code | |
| 2207 | + * @returns {HighlightResult} | |
| 2208 | + */ | |
| 2209 | + function justTextHighlightResult(code) { | |
| 2210 | + const result = { | |
| 2211 | + value: escape(code), | |
| 2212 | + illegal: false, | |
| 2213 | + relevance: 0, | |
| 2214 | + _top: PLAINTEXT_LANGUAGE, | |
| 2215 | + _emitter: new options.__emitter(options) | |
| 2216 | + }; | |
| 2217 | + result._emitter.addText(code); | |
| 2218 | + return result; | |
| 2219 | + } | |
| 2220 | + | |
| 2221 | + /** | |
| 2222 | + Highlighting with language detection. Accepts a string with the code to | |
| 2223 | + highlight. Returns an object with the following properties: | |
| 2224 | + | |
| 2225 | + - language (detected language) | |
| 2226 | + - relevance (int) | |
| 2227 | + - value (an HTML string with highlighting markup) | |
| 2228 | + - secondBest (object with the same structure for second-best heuristically | |
| 2229 | + detected language, may be absent) | |
| 2230 | + | |
| 2231 | + @param {string} code | |
| 2232 | + @param {Array<string>} [languageSubset] | |
| 2233 | + @returns {AutoHighlightResult} | |
| 2234 | + */ | |
| 2235 | + function highlightAuto(code, languageSubset) { | |
| 2236 | + languageSubset = languageSubset || options.languages || Object.keys(languages); | |
| 2237 | + const plaintext = justTextHighlightResult(code); | |
| 2238 | + | |
| 2239 | + const results = languageSubset.filter(getLanguage).filter(autoDetection).map(name => | |
| 2240 | + _highlight(name, code, false) | |
| 2241 | + ); | |
| 2242 | + results.unshift(plaintext); // plaintext is always an option | |
| 2243 | + | |
| 2244 | + const sorted = results.sort((a, b) => { | |
| 2245 | + // sort base on relevance | |
| 2246 | + if (a.relevance !== b.relevance) return b.relevance - a.relevance; | |
| 2247 | + | |
| 2248 | + // always award the tie to the base language | |
| 2249 | + // ie if C++ and Arduino are tied, it's more likely to be C++ | |
| 2250 | + if (a.language && b.language) { | |
| 2251 | + if (getLanguage(a.language).supersetOf === b.language) { | |
| 2252 | + return 1; | |
| 2253 | + } else if (getLanguage(b.language).supersetOf === a.language) { | |
| 2254 | + return -1; | |
| 2255 | + } | |
| 2256 | + } | |
| 2257 | + | |
| 2258 | + // otherwise say they are equal, which has the effect of sorting on | |
| 2259 | + // relevance while preserving the original ordering - which is how ties | |
| 2260 | + // have historically been settled, ie the language that comes first always | |
| 2261 | + // wins in the case of a tie | |
| 2262 | + return 0; | |
| 2263 | + }); | |
| 2264 | + | |
| 2265 | + const [best, secondBest] = sorted; | |
| 2266 | + | |
| 2267 | + /** @type {AutoHighlightResult} */ | |
| 2268 | + const result = best; | |
| 2269 | + result.secondBest = secondBest; | |
| 2270 | + | |
| 2271 | + return result; | |
| 2272 | + } | |
| 2273 | + | |
| 2274 | + /** | |
| 2275 | + * Builds new class name for block given the language name | |
| 2276 | + * | |
| 2277 | + * @param {HTMLElement} element | |
| 2278 | + * @param {string} [currentLang] | |
| 2279 | + * @param {string} [resultLang] | |
| 2280 | + */ | |
| 2281 | + function updateClassName(element, currentLang, resultLang) { | |
| 2282 | + const language = (currentLang && aliases[currentLang]) || resultLang; | |
| 2283 | + | |
| 2284 | + element.classList.add("hljs"); | |
| 2285 | + element.classList.add(`language-${language}`); | |
| 2286 | + } | |
| 2287 | + | |
| 2288 | + /** | |
| 2289 | + * Applies highlighting to a DOM node containing code. | |
| 2290 | + * | |
| 2291 | + * @param {HighlightedHTMLElement} element - the HTML element to highlight | |
| 2292 | + */ | |
| 2293 | + function highlightElement(element) { | |
| 2294 | + /** @type HTMLElement */ | |
| 2295 | + let node = null; | |
| 2296 | + const language = blockLanguage(element); | |
| 2297 | + | |
| 2298 | + if (shouldNotHighlight(language)) return; | |
| 2299 | + | |
| 2300 | + fire("before:highlightElement", | |
| 2301 | + { el: element, language }); | |
| 2302 | + | |
| 2303 | + if (element.dataset.highlighted) { | |
| 2304 | + console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.", element); | |
| 2305 | + return; | |
| 2306 | + } | |
| 2307 | + | |
| 2308 | + // we should be all text, no child nodes (unescaped HTML) - this is possibly | |
| 2309 | + // an HTML injection attack - it's likely too late if this is already in | |
| 2310 | + // production (the code has likely already done its damage by the time | |
| 2311 | + // we're seeing it)... but we yell loudly about this so that hopefully it's | |
| 2312 | + // more likely to be caught in development before making it to production | |
| 2313 | + if (element.children.length > 0) { | |
| 2314 | + if (!options.ignoreUnescapedHTML) { | |
| 2315 | + console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."); | |
| 2316 | + console.warn("https://github.com/highlightjs/highlight.js/wiki/security"); | |
| 2317 | + console.warn("The element with unescaped HTML:"); | |
| 2318 | + console.warn(element); | |
| 2319 | + } | |
| 2320 | + if (options.throwUnescapedHTML) { | |
| 2321 | + const err = new HTMLInjectionError( | |
| 2322 | + "One of your code blocks includes unescaped HTML.", | |
| 2323 | + element.innerHTML | |
| 2324 | + ); | |
| 2325 | + throw err; | |
| 2326 | + } | |
| 2327 | + } | |
| 2328 | + | |
| 2329 | + node = element; | |
| 2330 | + const text = node.textContent; | |
| 2331 | + const result = language ? highlight(text, { language, ignoreIllegals: true }) : highlightAuto(text); | |
| 2332 | + | |
| 2333 | + element.innerHTML = result.value; | |
| 2334 | + element.dataset.highlighted = "yes"; | |
| 2335 | + updateClassName(element, language, result.language); | |
| 2336 | + element.result = { | |
| 2337 | + language: result.language, | |
| 2338 | + // TODO: remove with version 11.0 | |
| 2339 | + re: result.relevance, | |
| 2340 | + relevance: result.relevance | |
| 2341 | + }; | |
| 2342 | + if (result.secondBest) { | |
| 2343 | + element.secondBest = { | |
| 2344 | + language: result.secondBest.language, | |
| 2345 | + relevance: result.secondBest.relevance | |
| 2346 | + }; | |
| 2347 | + } | |
| 2348 | + | |
| 2349 | + fire("after:highlightElement", { el: element, result, text }); | |
| 2350 | + } | |
| 2351 | + | |
| 2352 | + /** | |
| 2353 | + * Updates highlight.js global options with the passed options | |
| 2354 | + * | |
| 2355 | + * @param {Partial<HLJSOptions>} userOptions | |
| 2356 | + */ | |
| 2357 | + function configure(userOptions) { | |
| 2358 | + options = inherit(options, userOptions); | |
| 2359 | + } | |
| 2360 | + | |
| 2361 | + // TODO: remove v12, deprecated | |
| 2362 | + const initHighlighting = () => { | |
| 2363 | + highlightAll(); | |
| 2364 | + deprecated("10.6.0", "initHighlighting() deprecated. Use highlightAll() now."); | |
| 2365 | + }; | |
| 2366 | + | |
| 2367 | + // TODO: remove v12, deprecated | |
| 2368 | + function initHighlightingOnLoad() { | |
| 2369 | + highlightAll(); | |
| 2370 | + deprecated("10.6.0", "initHighlightingOnLoad() deprecated. Use highlightAll() now."); | |
| 2371 | + } | |
| 2372 | + | |
| 2373 | + let wantsHighlight = false; | |
| 2374 | + | |
| 2375 | + /** | |
| 2376 | + * auto-highlights all pre>code elements on the page | |
| 2377 | + */ | |
| 2378 | + function highlightAll() { | |
| 2379 | + function boot() { | |
| 2380 | + // if a highlight was requested before DOM was loaded, do now | |
| 2381 | + highlightAll(); | |
| 2382 | + } | |
| 2383 | + | |
| 2384 | + // if we are called too early in the loading process | |
| 2385 | + if (document.readyState === "loading") { | |
| 2386 | + // make sure the event listener is only added once | |
| 2387 | + if (!wantsHighlight) { | |
| 2388 | + window.addEventListener('DOMContentLoaded', boot, false); | |
| 2389 | + } | |
| 2390 | + wantsHighlight = true; | |
| 2391 | + return; | |
| 2392 | + } | |
| 2393 | + | |
| 2394 | + const blocks = document.querySelectorAll(options.cssSelector); | |
| 2395 | + blocks.forEach(highlightElement); | |
| 2396 | + } | |
| 2397 | + | |
| 2398 | + /** | |
| 2399 | + * Register a language grammar module | |
| 2400 | + * | |
| 2401 | + * @param {string} languageName | |
| 2402 | + * @param {LanguageFn} languageDefinition | |
| 2403 | + */ | |
| 2404 | + function registerLanguage(languageName, languageDefinition) { | |
| 2405 | + let lang = null; | |
| 2406 | + try { | |
| 2407 | + lang = languageDefinition(hljs); | |
| 2408 | + } catch (error$1) { | |
| 2409 | + error("Language definition for '{}' could not be registered.".replace("{}", languageName)); | |
| 2410 | + // hard or soft error | |
| 2411 | + if (!SAFE_MODE) { throw error$1; } else { error(error$1); } | |
| 2412 | + // languages that have serious errors are replaced with essentially a | |
| 2413 | + // "plaintext" stand-in so that the code blocks will still get normal | |
| 2414 | + // css classes applied to them - and one bad language won't break the | |
| 2415 | + // entire highlighter | |
| 2416 | + lang = PLAINTEXT_LANGUAGE; | |
| 2417 | + } | |
| 2418 | + // give it a temporary name if it doesn't have one in the meta-data | |
| 2419 | + if (!lang.name) lang.name = languageName; | |
| 2420 | + languages[languageName] = lang; | |
| 2421 | + lang.rawDefinition = languageDefinition.bind(null, hljs); | |
| 2422 | + | |
| 2423 | + if (lang.aliases) { | |
| 2424 | + registerAliases(lang.aliases, { languageName }); | |
| 2425 | + } | |
| 2426 | + } | |
| 2427 | + | |
| 2428 | + /** | |
| 2429 | + * Remove a language grammar module | |
| 2430 | + * | |
| 2431 | + * @param {string} languageName | |
| 2432 | + */ | |
| 2433 | + function unregisterLanguage(languageName) { | |
| 2434 | + delete languages[languageName]; | |
| 2435 | + for (const alias of Object.keys(aliases)) { | |
| 2436 | + if (aliases[alias] === languageName) { | |
| 2437 | + delete aliases[alias]; | |
| 2438 | + } | |
| 2439 | + } | |
| 2440 | + } | |
| 2441 | + | |
| 2442 | + /** | |
| 2443 | + * @returns {string[]} List of language internal names | |
| 2444 | + */ | |
| 2445 | + function listLanguages() { | |
| 2446 | + return Object.keys(languages); | |
| 2447 | + } | |
| 2448 | + | |
| 2449 | + /** | |
| 2450 | + * @param {string} name - name of the language to retrieve | |
| 2451 | + * @returns {Language | undefined} | |
| 2452 | + */ | |
| 2453 | + function getLanguage(name) { | |
| 2454 | + name = (name || '').toLowerCase(); | |
| 2455 | + return languages[name] || languages[aliases[name]]; | |
| 2456 | + } | |
| 2457 | + | |
| 2458 | + /** | |
| 2459 | + * | |
| 2460 | + * @param {string|string[]} aliasList - single alias or list of aliases | |
| 2461 | + * @param {{languageName: string}} opts | |
| 2462 | + */ | |
| 2463 | + function registerAliases(aliasList, { languageName }) { | |
| 2464 | + if (typeof aliasList === 'string') { | |
| 2465 | + aliasList = [aliasList]; | |
| 2466 | + } | |
| 2467 | + aliasList.forEach(alias => { aliases[alias.toLowerCase()] = languageName; }); | |
| 2468 | + } | |
| 2469 | + | |
| 2470 | + /** | |
| 2471 | + * Determines if a given language has auto-detection enabled | |
| 2472 | + * @param {string} name - name of the language | |
| 2473 | + */ | |
| 2474 | + function autoDetection(name) { | |
| 2475 | + const lang = getLanguage(name); | |
| 2476 | + return lang && !lang.disableAutodetect; | |
| 2477 | + } | |
| 2478 | + | |
| 2479 | + /** | |
| 2480 | + * Upgrades the old highlightBlock plugins to the new | |
| 2481 | + * highlightElement API | |
| 2482 | + * @param {HLJSPlugin} plugin | |
| 2483 | + */ | |
| 2484 | + function upgradePluginAPI(plugin) { | |
| 2485 | + // TODO: remove with v12 | |
| 2486 | + if (plugin["before:highlightBlock"] && !plugin["before:highlightElement"]) { | |
| 2487 | + plugin["before:highlightElement"] = (data) => { | |
| 2488 | + plugin["before:highlightBlock"]( | |
| 2489 | + Object.assign({ block: data.el }, data) | |
| 2490 | + ); | |
| 2491 | + }; | |
| 2492 | + } | |
| 2493 | + if (plugin["after:highlightBlock"] && !plugin["after:highlightElement"]) { | |
| 2494 | + plugin["after:highlightElement"] = (data) => { | |
| 2495 | + plugin["after:highlightBlock"]( | |
| 2496 | + Object.assign({ block: data.el }, data) | |
| 2497 | + ); | |
| 2498 | + }; | |
| 2499 | + } | |
| 2500 | + } | |
| 2501 | + | |
| 2502 | + /** | |
| 2503 | + * @param {HLJSPlugin} plugin | |
| 2504 | + */ | |
| 2505 | + function addPlugin(plugin) { | |
| 2506 | + upgradePluginAPI(plugin); | |
| 2507 | + plugins.push(plugin); | |
| 2508 | + } | |
| 2509 | + | |
| 2510 | + /** | |
| 2511 | + * @param {HLJSPlugin} plugin | |
| 2512 | + */ | |
| 2513 | + function removePlugin(plugin) { | |
| 2514 | + const index = plugins.indexOf(plugin); | |
| 2515 | + if (index !== -1) { | |
| 2516 | + plugins.splice(index, 1); | |
| 2517 | + } | |
| 2518 | + } | |
| 2519 | + | |
| 2520 | + /** | |
| 2521 | + * | |
| 2522 | + * @param {PluginEvent} event | |
| 2523 | + * @param {any} args | |
| 2524 | + */ | |
| 2525 | + function fire(event, args) { | |
| 2526 | + const cb = event; | |
| 2527 | + plugins.forEach(function(plugin) { | |
| 2528 | + if (plugin[cb]) { | |
| 2529 | + plugin[cb](args); | |
| 2530 | + } | |
| 2531 | + }); | |
| 2532 | + } | |
| 2533 | + | |
| 2534 | + /** | |
| 2535 | + * DEPRECATED | |
| 2536 | + * @param {HighlightedHTMLElement} el | |
| 2537 | + */ | |
| 2538 | + function deprecateHighlightBlock(el) { | |
| 2539 | + deprecated("10.7.0", "highlightBlock will be removed entirely in v12.0"); | |
| 2540 | + deprecated("10.7.0", "Please use highlightElement now."); | |
| 2541 | + | |
| 2542 | + return highlightElement(el); | |
| 2543 | + } | |
| 2544 | + | |
| 2545 | + /* Interface definition */ | |
| 2546 | + Object.assign(hljs, { | |
| 2547 | + highlight, | |
| 2548 | + highlightAuto, | |
| 2549 | + highlightAll, | |
| 2550 | + highlightElement, | |
| 2551 | + // TODO: Remove with v12 API | |
| 2552 | + highlightBlock: deprecateHighlightBlock, | |
| 2553 | + configure, | |
| 2554 | + initHighlighting, | |
| 2555 | + initHighlightingOnLoad, | |
| 2556 | + registerLanguage, | |
| 2557 | + unregisterLanguage, | |
| 2558 | + listLanguages, | |
| 2559 | + getLanguage, | |
| 2560 | + registerAliases, | |
| 2561 | + autoDetection, | |
| 2562 | + inherit, | |
| 2563 | + addPlugin, | |
| 2564 | + removePlugin | |
| 2565 | + }); | |
| 2566 | + | |
| 2567 | + hljs.debugMode = function() { SAFE_MODE = false; }; | |
| 2568 | + hljs.safeMode = function() { SAFE_MODE = true; }; | |
| 2569 | + hljs.versionString = version; | |
| 2570 | + | |
| 2571 | + hljs.regex = { | |
| 2572 | + concat: concat, | |
| 2573 | + lookahead: lookahead, | |
| 2574 | + either: either, | |
| 2575 | + optional: optional, | |
| 2576 | + anyNumberOfTimes: anyNumberOfTimes | |
| 2577 | + }; | |
| 2578 | + | |
| 2579 | + for (const key in MODES) { | |
| 2580 | + // @ts-ignore | |
| 2581 | + if (typeof MODES[key] === "object") { | |
| 2582 | + // @ts-ignore | |
| 2583 | + deepFreeze(MODES[key]); | |
| 2584 | + } | |
| 2585 | + } | |
| 2586 | + | |
| 2587 | + // merge all the modes/regexes into our main object | |
| 2588 | + Object.assign(hljs, MODES); | |
| 2589 | + | |
| 2590 | + return hljs; | |
| 2591 | +}; | |
| 2592 | + | |
| 2593 | +// Other names for the variable may break build script | |
| 2594 | +const highlight = HLJS({}); | |
| 2595 | + | |
| 2596 | +// returns a new instance of the highlighter to be used for extensions | |
| 2597 | +// check https://github.com/wooorm/lowlight/issues/47 | |
| 2598 | +highlight.newInstance = () => HLJS({}); | |
| 2599 | + | |
| 2600 | +export { highlight as default }; |
+++ src/main/webapp/publish/js/highlight/es/highlight.min.js
... | ... | @@ -0,0 +1,306 @@ |
| 1 | +/*! | |
| 2 | + Highlight.js v11.11.1 (git: 08cb242e7d) | |
| 3 | + (c) 2006-2025 Josh Goebel <hello@joshgoebel.com> and other contributors | |
| 4 | + License: BSD-3-Clause | |
| 5 | + */ | |
| 6 | +function e(t){return t instanceof Map?t.clear=t.delete=t.set=()=>{ | |
| 7 | +throw Error("map is read-only")}:t instanceof Set&&(t.add=t.clear=t.delete=()=>{ | |
| 8 | +throw Error("set is read-only") | |
| 9 | +}),Object.freeze(t),Object.getOwnPropertyNames(t).forEach((n=>{ | |
| 10 | +const i=t[n],s=typeof i;"object"!==s&&"function"!==s||Object.isFrozen(i)||e(i) | |
| 11 | +})),t}class t{constructor(e){ | |
| 12 | +void 0===e.data&&(e.data={}),this.data=e.data,this.isMatchIgnored=!1} | |
| 13 | +ignoreMatch(){this.isMatchIgnored=!0}}function n(e){ | |
| 14 | +return e.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""").replace(/'/g,"'") | |
| 15 | +}function i(e,...t){const n=Object.create(null);for(const t in e)n[t]=e[t] | |
| 16 | +;return t.forEach((e=>{for(const t in e)n[t]=e[t]})),n}const s=e=>!!e.scope | |
| 17 | +;class r{constructor(e,t){ | |
| 18 | +this.buffer="",this.classPrefix=t.classPrefix,e.walk(this)}addText(e){ | |
| 19 | +this.buffer+=n(e)}openNode(e){if(!s(e))return;const t=((e,{prefix:t})=>{ | |
| 20 | +if(e.startsWith("language:"))return e.replace("language:","language-") | |
| 21 | +;if(e.includes(".")){const n=e.split(".") | |
| 22 | +;return[`${t}${n.shift()}`,...n.map(((e,t)=>`${e}${"_".repeat(t+1)}`))].join(" ") | |
| 23 | +}return`${t}${e}`})(e.scope,{prefix:this.classPrefix});this.span(t)} | |
| 24 | +closeNode(e){s(e)&&(this.buffer+="</span>")}value(){return this.buffer}span(e){ | |
| 25 | +this.buffer+=`<span class="${e}">`}}const o=(e={})=>{const t={children:[]} | |
| 26 | +;return Object.assign(t,e),t};class a{constructor(){ | |
| 27 | +this.rootNode=o(),this.stack=[this.rootNode]}get top(){ | |
| 28 | +return this.stack[this.stack.length-1]}get root(){return this.rootNode}add(e){ | |
| 29 | +this.top.children.push(e)}openNode(e){const t=o({scope:e}) | |
| 30 | +;this.add(t),this.stack.push(t)}closeNode(){ | |
| 31 | +if(this.stack.length>1)return this.stack.pop()}closeAllNodes(){ | |
| 32 | +for(;this.closeNode(););}toJSON(){return JSON.stringify(this.rootNode,null,4)} | |
| 33 | +walk(e){return this.constructor._walk(e,this.rootNode)}static _walk(e,t){ | |
| 34 | +return"string"==typeof t?e.addText(t):t.children&&(e.openNode(t), | |
| 35 | +t.children.forEach((t=>this._walk(e,t))),e.closeNode(t)),e}static _collapse(e){ | |
| 36 | +"string"!=typeof e&&e.children&&(e.children.every((e=>"string"==typeof e))?e.children=[e.children.join("")]:e.children.forEach((e=>{ | |
| 37 | +a._collapse(e)})))}}class c extends a{constructor(e){super(),this.options=e} | |
| 38 | +addText(e){""!==e&&this.add(e)}startScope(e){this.openNode(e)}endScope(){ | |
| 39 | +this.closeNode()}__addSublanguage(e,t){const n=e.root | |
| 40 | +;t&&(n.scope="language:"+t),this.add(n)}toHTML(){ | |
| 41 | +return new r(this,this.options).value()}finalize(){ | |
| 42 | +return this.closeAllNodes(),!0}}function l(e){ | |
| 43 | +return e?"string"==typeof e?e:e.source:null}function g(e){return h("(?=",e,")")} | |
| 44 | +function u(e){return h("(?:",e,")*")}function d(e){return h("(?:",e,")?")} | |
| 45 | +function h(...e){return e.map((e=>l(e))).join("")}function f(...e){const t=(e=>{ | |
| 46 | +const t=e[e.length-1] | |
| 47 | +;return"object"==typeof t&&t.constructor===Object?(e.splice(e.length-1,1),t):{} | |
| 48 | +})(e);return"("+(t.capture?"":"?:")+e.map((e=>l(e))).join("|")+")"} | |
| 49 | +function p(e){return RegExp(e.toString()+"|").exec("").length-1} | |
| 50 | +const b=/\[(?:[^\\\]]|\\.)*\]|\(\??|\\([1-9][0-9]*)|\\./ | |
| 51 | +;function m(e,{joinWith:t}){let n=0;return e.map((e=>{n+=1;const t=n | |
| 52 | +;let i=l(e),s="";for(;i.length>0;){const e=b.exec(i);if(!e){s+=i;break} | |
| 53 | +s+=i.substring(0,e.index), | |
| 54 | +i=i.substring(e.index+e[0].length),"\\"===e[0][0]&&e[1]?s+="\\"+(Number(e[1])+t):(s+=e[0], | |
| 55 | +"("===e[0]&&n++)}return s})).map((e=>`(${e})`)).join(t)} | |
| 56 | +const E="[a-zA-Z]\\w*",x="[a-zA-Z_]\\w*",_="\\b\\d+(\\.\\d+)?",y="(-?)(\\b0[xX][a-fA-F0-9]+|(\\b\\d+(\\.\\d*)?|\\.\\d+)([eE][-+]?\\d+)?)",w="\\b(0b[01]+)",O={ | |
| 57 | +begin:"\\\\[\\s\\S]",relevance:0},k={scope:"string",begin:"'",end:"'", | |
| 58 | +illegal:"\\n",contains:[O]},v={scope:"string",begin:'"',end:'"',illegal:"\\n", | |
| 59 | +contains:[O]},N=(e,t,n={})=>{const s=i({scope:"comment",begin:e,end:t, | |
| 60 | +contains:[]},n);s.contains.push({scope:"doctag", | |
| 61 | +begin:"[ ]*(?=(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):)", | |
| 62 | +end:/(TODO|FIXME|NOTE|BUG|OPTIMIZE|HACK|XXX):/,excludeBegin:!0,relevance:0}) | |
| 63 | +;const r=f("I","a","is","so","us","to","at","if","in","it","on",/[A-Za-z]+['](d|ve|re|ll|t|s|n)/,/[A-Za-z]+[-][a-z]+/,/[A-Za-z][a-z]{2,}/) | |
| 64 | +;return s.contains.push({begin:h(/[ ]+/,"(",r,/[.]?[:]?([.][ ]|[ ])/,"){3}")}),s | |
| 65 | +},S=N("//","$"),M=N("/\\*","\\*/"),R=N("#","$");var A=Object.freeze({ | |
| 66 | +__proto__:null,APOS_STRING_MODE:k,BACKSLASH_ESCAPE:O,BINARY_NUMBER_MODE:{ | |
| 67 | +scope:"number",begin:w,relevance:0},BINARY_NUMBER_RE:w,COMMENT:N, | |
| 68 | +C_BLOCK_COMMENT_MODE:M,C_LINE_COMMENT_MODE:S,C_NUMBER_MODE:{scope:"number", | |
| 69 | +begin:y,relevance:0},C_NUMBER_RE:y,END_SAME_AS_BEGIN:e=>Object.assign(e,{ | |
| 70 | +"on:begin":(e,t)=>{t.data._beginMatch=e[1]},"on:end":(e,t)=>{ | |
| 71 | +t.data._beginMatch!==e[1]&&t.ignoreMatch()}}),HASH_COMMENT_MODE:R,IDENT_RE:E, | |
| 72 | +MATCH_NOTHING_RE:/\b\B/,METHOD_GUARD:{begin:"\\.\\s*"+x,relevance:0}, | |
| 73 | +NUMBER_MODE:{scope:"number",begin:_,relevance:0},NUMBER_RE:_, | |
| 74 | +PHRASAL_WORDS_MODE:{ | |
| 75 | +begin:/\b(a|an|the|are|I'm|isn't|don't|doesn't|won't|but|just|should|pretty|simply|enough|gonna|going|wtf|so|such|will|you|your|they|like|more)\b/ | |
| 76 | +},QUOTE_STRING_MODE:v,REGEXP_MODE:{scope:"regexp",begin:/\/(?=[^/\n]*\/)/, | |
| 77 | +end:/\/[gimuy]*/,contains:[O,{begin:/\[/,end:/\]/,relevance:0,contains:[O]}]}, | |
| 78 | +RE_STARTERS_RE:"!|!=|!==|%|%=|&|&&|&=|\\*|\\*=|\\+|\\+=|,|-|-=|/=|/|:|;|<<|<<=|<=|<|===|==|=|>>>=|>>=|>=|>>>|>>|>|\\?|\\[|\\{|\\(|\\^|\\^=|\\||\\|=|\\|\\||~", | |
| 79 | +SHEBANG:(e={})=>{const t=/^#![ ]*\// | |
| 80 | +;return e.binary&&(e.begin=h(t,/.*\b/,e.binary,/\b.*/)),i({scope:"meta",begin:t, | |
| 81 | +end:/$/,relevance:0,"on:begin":(e,t)=>{0!==e.index&&t.ignoreMatch()}},e)}, | |
| 82 | +TITLE_MODE:{scope:"title",begin:E,relevance:0},UNDERSCORE_IDENT_RE:x, | |
| 83 | +UNDERSCORE_TITLE_MODE:{scope:"title",begin:x,relevance:0}});function j(e,t){ | |
| 84 | +"."===e.input[e.index-1]&&t.ignoreMatch()}function I(e,t){ | |
| 85 | +void 0!==e.className&&(e.scope=e.className,delete e.className)}function T(e,t){ | |
| 86 | +t&&e.beginKeywords&&(e.begin="\\b("+e.beginKeywords.split(" ").join("|")+")(?!\\.)(?=\\b|\\s)", | |
| 87 | +e.__beforeBegin=j,e.keywords=e.keywords||e.beginKeywords,delete e.beginKeywords, | |
| 88 | +void 0===e.relevance&&(e.relevance=0))}function L(e,t){ | |
| 89 | +Array.isArray(e.illegal)&&(e.illegal=f(...e.illegal))}function B(e,t){ | |
| 90 | +if(e.match){ | |
| 91 | +if(e.begin||e.end)throw Error("begin & end are not supported with match") | |
| 92 | +;e.begin=e.match,delete e.match}}function P(e,t){ | |
| 93 | +void 0===e.relevance&&(e.relevance=1)}const D=(e,t)=>{if(!e.beforeMatch)return | |
| 94 | +;if(e.starts)throw Error("beforeMatch cannot be used with starts") | |
| 95 | +;const n=Object.assign({},e);Object.keys(e).forEach((t=>{delete e[t] | |
| 96 | +})),e.keywords=n.keywords,e.begin=h(n.beforeMatch,g(n.begin)),e.starts={ | |
| 97 | +relevance:0,contains:[Object.assign(n,{endsParent:!0})] | |
| 98 | +},e.relevance=0,delete n.beforeMatch | |
| 99 | +},H=["of","and","for","in","not","or","if","then","parent","list","value"] | |
| 100 | +;function C(e,t,n="keyword"){const i=Object.create(null) | |
| 101 | +;return"string"==typeof e?s(n,e.split(" ")):Array.isArray(e)?s(n,e):Object.keys(e).forEach((n=>{ | |
| 102 | +Object.assign(i,C(e[n],t,n))})),i;function s(e,n){ | |
| 103 | +t&&(n=n.map((e=>e.toLowerCase()))),n.forEach((t=>{const n=t.split("|") | |
| 104 | +;i[n[0]]=[e,$(n[0],n[1])]}))}}function $(e,t){ | |
| 105 | +return t?Number(t):(e=>H.includes(e.toLowerCase()))(e)?0:1}const U={},z=e=>{ | |
| 106 | +console.error(e)},W=(e,...t)=>{console.log("WARN: "+e,...t)},X=(e,t)=>{ | |
| 107 | +U[`${e}/${t}`]||(console.log(`Deprecated as of ${e}. ${t}`),U[`${e}/${t}`]=!0) | |
| 108 | +},G=Error();function K(e,t,{key:n}){let i=0;const s=e[n],r={},o={} | |
| 109 | +;for(let e=1;e<=t.length;e++)o[e+i]=s[e],r[e+i]=!0,i+=p(t[e-1]) | |
| 110 | +;e[n]=o,e[n]._emit=r,e[n]._multi=!0}function F(e){(e=>{ | |
| 111 | +e.scope&&"object"==typeof e.scope&&null!==e.scope&&(e.beginScope=e.scope, | |
| 112 | +delete e.scope)})(e),"string"==typeof e.beginScope&&(e.beginScope={ | |
| 113 | +_wrap:e.beginScope}),"string"==typeof e.endScope&&(e.endScope={_wrap:e.endScope | |
| 114 | +}),(e=>{if(Array.isArray(e.begin)){ | |
| 115 | +if(e.skip||e.excludeBegin||e.returnBegin)throw z("skip, excludeBegin, returnBegin not compatible with beginScope: {}"), | |
| 116 | +G | |
| 117 | +;if("object"!=typeof e.beginScope||null===e.beginScope)throw z("beginScope must be object"), | |
| 118 | +G;K(e,e.begin,{key:"beginScope"}),e.begin=m(e.begin,{joinWith:""})}})(e),(e=>{ | |
| 119 | +if(Array.isArray(e.end)){ | |
| 120 | +if(e.skip||e.excludeEnd||e.returnEnd)throw z("skip, excludeEnd, returnEnd not compatible with endScope: {}"), | |
| 121 | +G | |
| 122 | +;if("object"!=typeof e.endScope||null===e.endScope)throw z("endScope must be object"), | |
| 123 | +G;K(e,e.end,{key:"endScope"}),e.end=m(e.end,{joinWith:""})}})(e)}function Z(e){ | |
| 124 | +function t(t,n){ | |
| 125 | +return RegExp(l(t),"m"+(e.case_insensitive?"i":"")+(e.unicodeRegex?"u":"")+(n?"g":"")) | |
| 126 | +}class n{constructor(){ | |
| 127 | +this.matchIndexes={},this.regexes=[],this.matchAt=1,this.position=0} | |
| 128 | +addRule(e,t){ | |
| 129 | +t.position=this.position++,this.matchIndexes[this.matchAt]=t,this.regexes.push([t,e]), | |
| 130 | +this.matchAt+=p(e)+1}compile(){0===this.regexes.length&&(this.exec=()=>null) | |
| 131 | +;const e=this.regexes.map((e=>e[1]));this.matcherRe=t(m(e,{joinWith:"|" | |
| 132 | +}),!0),this.lastIndex=0}exec(e){this.matcherRe.lastIndex=this.lastIndex | |
| 133 | +;const t=this.matcherRe.exec(e);if(!t)return null | |
| 134 | +;const n=t.findIndex(((e,t)=>t>0&&void 0!==e)),i=this.matchIndexes[n] | |
| 135 | +;return t.splice(0,n),Object.assign(t,i)}}class s{constructor(){ | |
| 136 | +this.rules=[],this.multiRegexes=[], | |
| 137 | +this.count=0,this.lastIndex=0,this.regexIndex=0}getMatcher(e){ | |
| 138 | +if(this.multiRegexes[e])return this.multiRegexes[e];const t=new n | |
| 139 | +;return this.rules.slice(e).forEach((([e,n])=>t.addRule(e,n))), | |
| 140 | +t.compile(),this.multiRegexes[e]=t,t}resumingScanAtSamePosition(){ | |
| 141 | +return 0!==this.regexIndex}considerAll(){this.regexIndex=0}addRule(e,t){ | |
| 142 | +this.rules.push([e,t]),"begin"===t.type&&this.count++}exec(e){ | |
| 143 | +const t=this.getMatcher(this.regexIndex);t.lastIndex=this.lastIndex | |
| 144 | +;let n=t.exec(e) | |
| 145 | +;if(this.resumingScanAtSamePosition())if(n&&n.index===this.lastIndex);else{ | |
| 146 | +const t=this.getMatcher(0);t.lastIndex=this.lastIndex+1,n=t.exec(e)} | |
| 147 | +return n&&(this.regexIndex+=n.position+1, | |
| 148 | +this.regexIndex===this.count&&this.considerAll()),n}} | |
| 149 | +if(e.compilerExtensions||(e.compilerExtensions=[]), | |
| 150 | +e.contains&&e.contains.includes("self"))throw Error("ERR: contains `self` is not supported at the top-level of a language. See documentation.") | |
| 151 | +;return e.classNameAliases=i(e.classNameAliases||{}),function n(r,o){const a=r | |
| 152 | +;if(r.isCompiled)return a | |
| 153 | +;[I,B,F,D].forEach((e=>e(r,o))),e.compilerExtensions.forEach((e=>e(r,o))), | |
| 154 | +r.__beforeBegin=null,[T,L,P].forEach((e=>e(r,o))),r.isCompiled=!0;let c=null | |
| 155 | +;return"object"==typeof r.keywords&&r.keywords.$pattern&&(r.keywords=Object.assign({},r.keywords), | |
| 156 | +c=r.keywords.$pattern, | |
| 157 | +delete r.keywords.$pattern),c=c||/\w+/,r.keywords&&(r.keywords=C(r.keywords,e.case_insensitive)), | |
| 158 | +a.keywordPatternRe=t(c,!0), | |
| 159 | +o&&(r.begin||(r.begin=/\B|\b/),a.beginRe=t(a.begin),r.end||r.endsWithParent||(r.end=/\B|\b/), | |
| 160 | +r.end&&(a.endRe=t(a.end)), | |
| 161 | +a.terminatorEnd=l(a.end)||"",r.endsWithParent&&o.terminatorEnd&&(a.terminatorEnd+=(r.end?"|":"")+o.terminatorEnd)), | |
| 162 | +r.illegal&&(a.illegalRe=t(r.illegal)), | |
| 163 | +r.contains||(r.contains=[]),r.contains=[].concat(...r.contains.map((e=>(e=>(e.variants&&!e.cachedVariants&&(e.cachedVariants=e.variants.map((t=>i(e,{ | |
| 164 | +variants:null},t)))),e.cachedVariants?e.cachedVariants:V(e)?i(e,{ | |
| 165 | +starts:e.starts?i(e.starts):null | |
| 166 | +}):Object.isFrozen(e)?i(e):e))("self"===e?r:e)))),r.contains.forEach((e=>{n(e,a) | |
| 167 | +})),r.starts&&n(r.starts,o),a.matcher=(e=>{const t=new s | |
| 168 | +;return e.contains.forEach((e=>t.addRule(e.begin,{rule:e,type:"begin" | |
| 169 | +}))),e.terminatorEnd&&t.addRule(e.terminatorEnd,{type:"end" | |
| 170 | +}),e.illegal&&t.addRule(e.illegal,{type:"illegal"}),t})(a),a}(e)}function V(e){ | |
| 171 | +return!!e&&(e.endsWithParent||V(e.starts))}class q extends Error{ | |
| 172 | +constructor(e,t){super(e),this.name="HTMLInjectionError",this.html=t}} | |
| 173 | +const J=n,Y=i,Q=Symbol("nomatch"),ee=n=>{ | |
| 174 | +const i=Object.create(null),s=Object.create(null),r=[];let o=!0 | |
| 175 | +;const a="Could not find the language '{}', did you forget to load/include a language module?",l={ | |
| 176 | +disableAutodetect:!0,name:"Plain text",contains:[]};let p={ | |
| 177 | +ignoreUnescapedHTML:!1,throwUnescapedHTML:!1,noHighlightRe:/^(no-?highlight)$/i, | |
| 178 | +languageDetectRe:/\blang(?:uage)?-([\w-]+)\b/i,classPrefix:"hljs-", | |
| 179 | +cssSelector:"pre code",languages:null,__emitter:c};function b(e){ | |
| 180 | +return p.noHighlightRe.test(e)}function m(e,t,n){let i="",s="" | |
| 181 | +;"object"==typeof t?(i=e, | |
| 182 | +n=t.ignoreIllegals,s=t.language):(X("10.7.0","highlight(lang, code, ...args) has been deprecated."), | |
| 183 | +X("10.7.0","Please use highlight(code, options) instead.\nhttps://github.com/highlightjs/highlight.js/issues/2277"), | |
| 184 | +s=e,i=t),void 0===n&&(n=!0);const r={code:i,language:s};N("before:highlight",r) | |
| 185 | +;const o=r.result?r.result:E(r.language,r.code,n) | |
| 186 | +;return o.code=r.code,N("after:highlight",o),o}function E(e,n,s,r){ | |
| 187 | +const c=Object.create(null);function l(){if(!N.keywords)return void M.addText(R) | |
| 188 | +;let e=0;N.keywordPatternRe.lastIndex=0;let t=N.keywordPatternRe.exec(R),n="" | |
| 189 | +;for(;t;){n+=R.substring(e,t.index) | |
| 190 | +;const s=w.case_insensitive?t[0].toLowerCase():t[0],r=(i=s,N.keywords[i]);if(r){ | |
| 191 | +const[e,i]=r | |
| 192 | +;if(M.addText(n),n="",c[s]=(c[s]||0)+1,c[s]<=7&&(A+=i),e.startsWith("_"))n+=t[0];else{ | |
| 193 | +const n=w.classNameAliases[e]||e;u(t[0],n)}}else n+=t[0] | |
| 194 | +;e=N.keywordPatternRe.lastIndex,t=N.keywordPatternRe.exec(R)}var i | |
| 195 | +;n+=R.substring(e),M.addText(n)}function g(){null!=N.subLanguage?(()=>{ | |
| 196 | +if(""===R)return;let e=null;if("string"==typeof N.subLanguage){ | |
| 197 | +if(!i[N.subLanguage])return void M.addText(R) | |
| 198 | +;e=E(N.subLanguage,R,!0,S[N.subLanguage]),S[N.subLanguage]=e._top | |
| 199 | +}else e=x(R,N.subLanguage.length?N.subLanguage:null) | |
| 200 | +;N.relevance>0&&(A+=e.relevance),M.__addSublanguage(e._emitter,e.language) | |
| 201 | +})():l(),R=""}function u(e,t){ | |
| 202 | +""!==e&&(M.startScope(t),M.addText(e),M.endScope())}function d(e,t){let n=1 | |
| 203 | +;const i=t.length-1;for(;n<=i;){if(!e._emit[n]){n++;continue} | |
| 204 | +const i=w.classNameAliases[e[n]]||e[n],s=t[n];i?u(s,i):(R=s,l(),R=""),n++}} | |
| 205 | +function h(e,t){ | |
| 206 | +return e.scope&&"string"==typeof e.scope&&M.openNode(w.classNameAliases[e.scope]||e.scope), | |
| 207 | +e.beginScope&&(e.beginScope._wrap?(u(R,w.classNameAliases[e.beginScope._wrap]||e.beginScope._wrap), | |
| 208 | +R=""):e.beginScope._multi&&(d(e.beginScope,t),R="")),N=Object.create(e,{parent:{ | |
| 209 | +value:N}}),N}function f(e,n,i){let s=((e,t)=>{const n=e&&e.exec(t) | |
| 210 | +;return n&&0===n.index})(e.endRe,i);if(s){if(e["on:end"]){const i=new t(e) | |
| 211 | +;e["on:end"](n,i),i.isMatchIgnored&&(s=!1)}if(s){ | |
| 212 | +for(;e.endsParent&&e.parent;)e=e.parent;return e}} | |
| 213 | +if(e.endsWithParent)return f(e.parent,n,i)}function b(e){ | |
| 214 | +return 0===N.matcher.regexIndex?(R+=e[0],1):(T=!0,0)}function m(e){ | |
| 215 | +const t=e[0],i=n.substring(e.index),s=f(N,e,i);if(!s)return Q;const r=N | |
| 216 | +;N.endScope&&N.endScope._wrap?(g(), | |
| 217 | +u(t,N.endScope._wrap)):N.endScope&&N.endScope._multi?(g(), | |
| 218 | +d(N.endScope,e)):r.skip?R+=t:(r.returnEnd||r.excludeEnd||(R+=t), | |
| 219 | +g(),r.excludeEnd&&(R=t));do{ | |
| 220 | +N.scope&&M.closeNode(),N.skip||N.subLanguage||(A+=N.relevance),N=N.parent | |
| 221 | +}while(N!==s.parent);return s.starts&&h(s.starts,e),r.returnEnd?0:t.length} | |
| 222 | +let _={};function y(i,r){const a=r&&r[0];if(R+=i,null==a)return g(),0 | |
| 223 | +;if("begin"===_.type&&"end"===r.type&&_.index===r.index&&""===a){ | |
| 224 | +if(R+=n.slice(r.index,r.index+1),!o){const t=Error(`0 width match regex (${e})`) | |
| 225 | +;throw t.languageName=e,t.badRule=_.rule,t}return 1} | |
| 226 | +if(_=r,"begin"===r.type)return(e=>{ | |
| 227 | +const n=e[0],i=e.rule,s=new t(i),r=[i.__beforeBegin,i["on:begin"]] | |
| 228 | +;for(const t of r)if(t&&(t(e,s),s.isMatchIgnored))return b(n) | |
| 229 | +;return i.skip?R+=n:(i.excludeBegin&&(R+=n), | |
| 230 | +g(),i.returnBegin||i.excludeBegin||(R=n)),h(i,e),i.returnBegin?0:n.length})(r) | |
| 231 | +;if("illegal"===r.type&&!s){ | |
| 232 | +const e=Error('Illegal lexeme "'+a+'" for mode "'+(N.scope||"<unnamed>")+'"') | |
| 233 | +;throw e.mode=N,e}if("end"===r.type){const e=m(r);if(e!==Q)return e} | |
| 234 | +if("illegal"===r.type&&""===a)return R+="\n",1 | |
| 235 | +;if(I>1e5&&I>3*r.index)throw Error("potential infinite loop, way more iterations than matches") | |
| 236 | +;return R+=a,a.length}const w=O(e) | |
| 237 | +;if(!w)throw z(a.replace("{}",e)),Error('Unknown language: "'+e+'"') | |
| 238 | +;const k=Z(w);let v="",N=r||k;const S={},M=new p.__emitter(p);(()=>{const e=[] | |
| 239 | +;for(let t=N;t!==w;t=t.parent)t.scope&&e.unshift(t.scope) | |
| 240 | +;e.forEach((e=>M.openNode(e)))})();let R="",A=0,j=0,I=0,T=!1;try{ | |
| 241 | +if(w.__emitTokens)w.__emitTokens(n,M);else{for(N.matcher.considerAll();;){ | |
| 242 | +I++,T?T=!1:N.matcher.considerAll(),N.matcher.lastIndex=j | |
| 243 | +;const e=N.matcher.exec(n);if(!e)break;const t=y(n.substring(j,e.index),e) | |
| 244 | +;j=e.index+t}y(n.substring(j))}return M.finalize(),v=M.toHTML(),{language:e, | |
| 245 | +value:v,relevance:A,illegal:!1,_emitter:M,_top:N}}catch(t){ | |
| 246 | +if(t.message&&t.message.includes("Illegal"))return{language:e,value:J(n), | |
| 247 | +illegal:!0,relevance:0,_illegalBy:{message:t.message,index:j, | |
| 248 | +context:n.slice(j-100,j+100),mode:t.mode,resultSoFar:v},_emitter:M};if(o)return{ | |
| 249 | +language:e,value:J(n),illegal:!1,relevance:0,errorRaised:t,_emitter:M,_top:N} | |
| 250 | +;throw t}}function x(e,t){t=t||p.languages||Object.keys(i);const n=(e=>{ | |
| 251 | +const t={value:J(e),illegal:!1,relevance:0,_top:l,_emitter:new p.__emitter(p)} | |
| 252 | +;return t._emitter.addText(e),t})(e),s=t.filter(O).filter(v).map((t=>E(t,e,!1))) | |
| 253 | +;s.unshift(n);const r=s.sort(((e,t)=>{ | |
| 254 | +if(e.relevance!==t.relevance)return t.relevance-e.relevance | |
| 255 | +;if(e.language&&t.language){if(O(e.language).supersetOf===t.language)return 1 | |
| 256 | +;if(O(t.language).supersetOf===e.language)return-1}return 0})),[o,a]=r,c=o | |
| 257 | +;return c.secondBest=a,c}function _(e){let t=null;const n=(e=>{ | |
| 258 | +let t=e.className+" ";t+=e.parentNode?e.parentNode.className:"" | |
| 259 | +;const n=p.languageDetectRe.exec(t);if(n){const t=O(n[1]) | |
| 260 | +;return t||(W(a.replace("{}",n[1])), | |
| 261 | +W("Falling back to no-highlight mode for this block.",e)),t?n[1]:"no-highlight"} | |
| 262 | +return t.split(/\s+/).find((e=>b(e)||O(e)))})(e);if(b(n))return | |
| 263 | +;if(N("before:highlightElement",{el:e,language:n | |
| 264 | +}),e.dataset.highlighted)return void console.log("Element previously highlighted. To highlight again, first unset `dataset.highlighted`.",e) | |
| 265 | +;if(e.children.length>0&&(p.ignoreUnescapedHTML||(console.warn("One of your code blocks includes unescaped HTML. This is a potentially serious security risk."), | |
| 266 | +console.warn("https://github.com/highlightjs/highlight.js/wiki/security"), | |
| 267 | +console.warn("The element with unescaped HTML:"), | |
| 268 | +console.warn(e)),p.throwUnescapedHTML))throw new q("One of your code blocks includes unescaped HTML.",e.innerHTML) | |
| 269 | +;t=e;const i=t.textContent,r=n?m(i,{language:n,ignoreIllegals:!0}):x(i) | |
| 270 | +;e.innerHTML=r.value,e.dataset.highlighted="yes",((e,t,n)=>{const i=t&&s[t]||n | |
| 271 | +;e.classList.add("hljs"),e.classList.add("language-"+i) | |
| 272 | +})(e,n,r.language),e.result={language:r.language,re:r.relevance, | |
| 273 | +relevance:r.relevance},r.secondBest&&(e.secondBest={ | |
| 274 | +language:r.secondBest.language,relevance:r.secondBest.relevance | |
| 275 | +}),N("after:highlightElement",{el:e,result:r,text:i})}let y=!1;function w(){ | |
| 276 | +if("loading"===document.readyState)return y||window.addEventListener("DOMContentLoaded",(()=>{ | |
| 277 | +w()}),!1),void(y=!0);document.querySelectorAll(p.cssSelector).forEach(_)} | |
| 278 | +function O(e){return e=(e||"").toLowerCase(),i[e]||i[s[e]]} | |
| 279 | +function k(e,{languageName:t}){"string"==typeof e&&(e=[e]),e.forEach((e=>{ | |
| 280 | +s[e.toLowerCase()]=t}))}function v(e){const t=O(e) | |
| 281 | +;return t&&!t.disableAutodetect}function N(e,t){const n=e;r.forEach((e=>{ | |
| 282 | +e[n]&&e[n](t)}))}Object.assign(n,{highlight:m,highlightAuto:x,highlightAll:w, | |
| 283 | +highlightElement:_, | |
| 284 | +highlightBlock:e=>(X("10.7.0","highlightBlock will be removed entirely in v12.0"), | |
| 285 | +X("10.7.0","Please use highlightElement now."),_(e)),configure:e=>{p=Y(p,e)}, | |
| 286 | +initHighlighting:()=>{ | |
| 287 | +w(),X("10.6.0","initHighlighting() deprecated. Use highlightAll() now.")}, | |
| 288 | +initHighlightingOnLoad:()=>{ | |
| 289 | +w(),X("10.6.0","initHighlightingOnLoad() deprecated. Use highlightAll() now.") | |
| 290 | +},registerLanguage:(e,t)=>{let s=null;try{s=t(n)}catch(t){ | |
| 291 | +if(z("Language definition for '{}' could not be registered.".replace("{}",e)), | |
| 292 | +!o)throw t;z(t),s=l} | |
| 293 | +s.name||(s.name=e),i[e]=s,s.rawDefinition=t.bind(null,n),s.aliases&&k(s.aliases,{ | |
| 294 | +languageName:e})},unregisterLanguage:e=>{delete i[e] | |
| 295 | +;for(const t of Object.keys(s))s[t]===e&&delete s[t]}, | |
| 296 | +listLanguages:()=>Object.keys(i),getLanguage:O,registerAliases:k, | |
| 297 | +autoDetection:v,inherit:Y,addPlugin:e=>{(e=>{ | |
| 298 | +e["before:highlightBlock"]&&!e["before:highlightElement"]&&(e["before:highlightElement"]=t=>{ | |
| 299 | +e["before:highlightBlock"](Object.assign({block:t.el},t)) | |
| 300 | +}),e["after:highlightBlock"]&&!e["after:highlightElement"]&&(e["after:highlightElement"]=t=>{ | |
| 301 | +e["after:highlightBlock"](Object.assign({block:t.el},t))})})(e),r.push(e)}, | |
| 302 | +removePlugin:e=>{const t=r.indexOf(e);-1!==t&&r.splice(t,1)}}),n.debugMode=()=>{ | |
| 303 | +o=!1},n.safeMode=()=>{o=!0},n.versionString="11.11.1",n.regex={concat:h, | |
| 304 | +lookahead:g,either:f,optional:d,anyNumberOfTimes:u} | |
| 305 | +;for(const t in A)"object"==typeof A[t]&&e(A[t]);return Object.assign(n,A),n | |
| 306 | +},te=ee({});te.newInstance=()=>ee({});export{te as default};(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/http.js
... | ... | @@ -0,0 +1,105 @@ |
| 1 | +/*! `http` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar = (function () { | |
| 3 | + 'use strict'; | |
| 4 | + | |
| 5 | + /* | |
| 6 | + Language: HTTP | |
| 7 | + Description: HTTP request and response headers with automatic body highlighting | |
| 8 | + Author: Ivan Sagalaev <maniac@softwaremaniacs.org> | |
| 9 | + Category: protocols, web | |
| 10 | + Website: https://developer.mozilla.org/en-US/docs/Web/HTTP/Overview | |
| 11 | + */ | |
| 12 | + | |
| 13 | + function http(hljs) { | |
| 14 | + const regex = hljs.regex; | |
| 15 | + const VERSION = 'HTTP/([32]|1\\.[01])'; | |
| 16 | + const HEADER_NAME = /[A-Za-z][A-Za-z0-9-]*/; | |
| 17 | + const HEADER = { | |
| 18 | + className: 'attribute', | |
| 19 | + begin: regex.concat('^', HEADER_NAME, '(?=\\:\\s)'), | |
| 20 | + starts: { contains: [ | |
| 21 | + { | |
| 22 | + className: "punctuation", | |
| 23 | + begin: /: /, | |
| 24 | + relevance: 0, | |
| 25 | + starts: { | |
| 26 | + end: '$', | |
| 27 | + relevance: 0 | |
| 28 | + } | |
| 29 | + } | |
| 30 | + ] } | |
| 31 | + }; | |
| 32 | + const HEADERS_AND_BODY = [ | |
| 33 | + HEADER, | |
| 34 | + { | |
| 35 | + begin: '\\n\\n', | |
| 36 | + starts: { | |
| 37 | + subLanguage: [], | |
| 38 | + endsWithParent: true | |
| 39 | + } | |
| 40 | + } | |
| 41 | + ]; | |
| 42 | + | |
| 43 | + return { | |
| 44 | + name: 'HTTP', | |
| 45 | + aliases: [ 'https' ], | |
| 46 | + illegal: /\S/, | |
| 47 | + contains: [ | |
| 48 | + // response | |
| 49 | + { | |
| 50 | + begin: '^(?=' + VERSION + " \\d{3})", | |
| 51 | + end: /$/, | |
| 52 | + contains: [ | |
| 53 | + { | |
| 54 | + className: "meta", | |
| 55 | + begin: VERSION | |
| 56 | + }, | |
| 57 | + { | |
| 58 | + className: 'number', | |
| 59 | + begin: '\\b\\d{3}\\b' | |
| 60 | + } | |
| 61 | + ], | |
| 62 | + starts: { | |
| 63 | + end: /\b\B/, | |
| 64 | + illegal: /\S/, | |
| 65 | + contains: HEADERS_AND_BODY | |
| 66 | + } | |
| 67 | + }, | |
| 68 | + // request | |
| 69 | + { | |
| 70 | + begin: '(?=^[A-Z]+ (.*?) ' + VERSION + '$)', | |
| 71 | + end: /$/, | |
| 72 | + contains: [ | |
| 73 | + { | |
| 74 | + className: 'string', | |
| 75 | + begin: ' ', | |
| 76 | + end: ' ', | |
| 77 | + excludeBegin: true, | |
| 78 | + excludeEnd: true | |
| 79 | + }, | |
| 80 | + { | |
| 81 | + className: "meta", | |
| 82 | + begin: VERSION | |
| 83 | + }, | |
| 84 | + { | |
| 85 | + className: 'keyword', | |
| 86 | + begin: '[A-Z]+' | |
| 87 | + } | |
| 88 | + ], | |
| 89 | + starts: { | |
| 90 | + end: /\b\B/, | |
| 91 | + illegal: /\S/, | |
| 92 | + contains: HEADERS_AND_BODY | |
| 93 | + } | |
| 94 | + }, | |
| 95 | + // to allow headers to work even without a preamble | |
| 96 | + hljs.inherit(HEADER, { relevance: 0 }) | |
| 97 | + ] | |
| 98 | + }; | |
| 99 | + } | |
| 100 | + | |
| 101 | + return http; | |
| 102 | + | |
| 103 | +})(); | |
| 104 | +; | |
| 105 | +export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/http.min.js
... | ... | @@ -0,0 +1,14 @@ |
| 1 | +/*! `http` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar=(()=>{"use strict";return e=>{const a="HTTP/([32]|1\\.[01])",n={ | |
| 3 | +className:"attribute", | |
| 4 | +begin:e.regex.concat("^",/[A-Za-z][A-Za-z0-9-]*/,"(?=\\:\\s)"),starts:{ | |
| 5 | +contains:[{className:"punctuation",begin:/: /,relevance:0,starts:{end:"$", | |
| 6 | +relevance:0}}]}},s=[n,{begin:"\\n\\n",starts:{subLanguage:[],endsWithParent:!0} | |
| 7 | +}];return{name:"HTTP",aliases:["https"],illegal:/\S/,contains:[{ | |
| 8 | +begin:"^(?="+a+" \\d{3})",end:/$/,contains:[{className:"meta",begin:a},{ | |
| 9 | +className:"number",begin:"\\b\\d{3}\\b"}],starts:{end:/\b\B/,illegal:/\S/, | |
| 10 | +contains:s}},{begin:"(?=^[A-Z]+ (.*?) "+a+"$)",end:/$/,contains:[{ | |
| 11 | +className:"string",begin:" ",end:" ",excludeBegin:!0,excludeEnd:!0},{ | |
| 12 | +className:"meta",begin:a},{className:"keyword",begin:"[A-Z]+"}],starts:{ | |
| 13 | +end:/\b\B/,illegal:/\S/,contains:s}},e.inherit(n,{relevance:0})]}}})() | |
| 14 | +;export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/java.js
... | ... | @@ -0,0 +1,299 @@ |
| 1 | +/*! `java` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar = (function () { | |
| 3 | + 'use strict'; | |
| 4 | + | |
| 5 | + // https://docs.oracle.com/javase/specs/jls/se15/html/jls-3.html#jls-3.10 | |
| 6 | + var decimalDigits = '[0-9](_*[0-9])*'; | |
| 7 | + var frac = `\\.(${decimalDigits})`; | |
| 8 | + var hexDigits = '[0-9a-fA-F](_*[0-9a-fA-F])*'; | |
| 9 | + var NUMERIC = { | |
| 10 | + className: 'number', | |
| 11 | + variants: [ | |
| 12 | + // DecimalFloatingPointLiteral | |
| 13 | + // including ExponentPart | |
| 14 | + { begin: `(\\b(${decimalDigits})((${frac})|\\.)?|(${frac}))` + | |
| 15 | + `[eE][+-]?(${decimalDigits})[fFdD]?\\b` }, | |
| 16 | + // excluding ExponentPart | |
| 17 | + { begin: `\\b(${decimalDigits})((${frac})[fFdD]?\\b|\\.([fFdD]\\b)?)` }, | |
| 18 | + { begin: `(${frac})[fFdD]?\\b` }, | |
| 19 | + { begin: `\\b(${decimalDigits})[fFdD]\\b` }, | |
| 20 | + | |
| 21 | + // HexadecimalFloatingPointLiteral | |
| 22 | + { begin: `\\b0[xX]((${hexDigits})\\.?|(${hexDigits})?\\.(${hexDigits}))` + | |
| 23 | + `[pP][+-]?(${decimalDigits})[fFdD]?\\b` }, | |
| 24 | + | |
| 25 | + // DecimalIntegerLiteral | |
| 26 | + { begin: '\\b(0|[1-9](_*[0-9])*)[lL]?\\b' }, | |
| 27 | + | |
| 28 | + // HexIntegerLiteral | |
| 29 | + { begin: `\\b0[xX](${hexDigits})[lL]?\\b` }, | |
| 30 | + | |
| 31 | + // OctalIntegerLiteral | |
| 32 | + { begin: '\\b0(_*[0-7])*[lL]?\\b' }, | |
| 33 | + | |
| 34 | + // BinaryIntegerLiteral | |
| 35 | + { begin: '\\b0[bB][01](_*[01])*[lL]?\\b' }, | |
| 36 | + ], | |
| 37 | + relevance: 0 | |
| 38 | + }; | |
| 39 | + | |
| 40 | + /* | |
| 41 | + Language: Java | |
| 42 | + Author: Vsevolod Solovyov <vsevolod.solovyov@gmail.com> | |
| 43 | + Category: common, enterprise | |
| 44 | + Website: https://www.java.com/ | |
| 45 | + */ | |
| 46 | + | |
| 47 | + | |
| 48 | + /** | |
| 49 | + * Allows recursive regex expressions to a given depth | |
| 50 | + * | |
| 51 | + * ie: recurRegex("(abc~~~)", /~~~/g, 2) becomes: | |
| 52 | + * (abc(abc(abc))) | |
| 53 | + * | |
| 54 | + * @param {string} re | |
| 55 | + * @param {RegExp} substitution (should be a g mode regex) | |
| 56 | + * @param {number} depth | |
| 57 | + * @returns {string}`` | |
| 58 | + */ | |
| 59 | + function recurRegex(re, substitution, depth) { | |
| 60 | + if (depth === -1) return ""; | |
| 61 | + | |
| 62 | + return re.replace(substitution, _ => { | |
| 63 | + return recurRegex(re, substitution, depth - 1); | |
| 64 | + }); | |
| 65 | + } | |
| 66 | + | |
| 67 | + /** @type LanguageFn */ | |
| 68 | + function java(hljs) { | |
| 69 | + const regex = hljs.regex; | |
| 70 | + const JAVA_IDENT_RE = '[\u00C0-\u02B8a-zA-Z_$][\u00C0-\u02B8a-zA-Z_$0-9]*'; | |
| 71 | + const GENERIC_IDENT_RE = JAVA_IDENT_RE | |
| 72 | + + recurRegex('(?:<' + JAVA_IDENT_RE + '~~~(?:\\s*,\\s*' + JAVA_IDENT_RE + '~~~)*>)?', /~~~/g, 2); | |
| 73 | + const MAIN_KEYWORDS = [ | |
| 74 | + 'synchronized', | |
| 75 | + 'abstract', | |
| 76 | + 'private', | |
| 77 | + 'var', | |
| 78 | + 'static', | |
| 79 | + 'if', | |
| 80 | + 'const ', | |
| 81 | + 'for', | |
| 82 | + 'while', | |
| 83 | + 'strictfp', | |
| 84 | + 'finally', | |
| 85 | + 'protected', | |
| 86 | + 'import', | |
| 87 | + 'native', | |
| 88 | + 'final', | |
| 89 | + 'void', | |
| 90 | + 'enum', | |
| 91 | + 'else', | |
| 92 | + 'break', | |
| 93 | + 'transient', | |
| 94 | + 'catch', | |
| 95 | + 'instanceof', | |
| 96 | + 'volatile', | |
| 97 | + 'case', | |
| 98 | + 'assert', | |
| 99 | + 'package', | |
| 100 | + 'default', | |
| 101 | + 'public', | |
| 102 | + 'try', | |
| 103 | + 'switch', | |
| 104 | + 'continue', | |
| 105 | + 'throws', | |
| 106 | + 'protected', | |
| 107 | + 'public', | |
| 108 | + 'private', | |
| 109 | + 'module', | |
| 110 | + 'requires', | |
| 111 | + 'exports', | |
| 112 | + 'do', | |
| 113 | + 'sealed', | |
| 114 | + 'yield', | |
| 115 | + 'permits', | |
| 116 | + 'goto', | |
| 117 | + 'when' | |
| 118 | + ]; | |
| 119 | + | |
| 120 | + const BUILT_INS = [ | |
| 121 | + 'super', | |
| 122 | + 'this' | |
| 123 | + ]; | |
| 124 | + | |
| 125 | + const LITERALS = [ | |
| 126 | + 'false', | |
| 127 | + 'true', | |
| 128 | + 'null' | |
| 129 | + ]; | |
| 130 | + | |
| 131 | + const TYPES = [ | |
| 132 | + 'char', | |
| 133 | + 'boolean', | |
| 134 | + 'long', | |
| 135 | + 'float', | |
| 136 | + 'int', | |
| 137 | + 'byte', | |
| 138 | + 'short', | |
| 139 | + 'double' | |
| 140 | + ]; | |
| 141 | + | |
| 142 | + const KEYWORDS = { | |
| 143 | + keyword: MAIN_KEYWORDS, | |
| 144 | + literal: LITERALS, | |
| 145 | + type: TYPES, | |
| 146 | + built_in: BUILT_INS | |
| 147 | + }; | |
| 148 | + | |
| 149 | + const ANNOTATION = { | |
| 150 | + className: 'meta', | |
| 151 | + begin: '@' + JAVA_IDENT_RE, | |
| 152 | + contains: [ | |
| 153 | + { | |
| 154 | + begin: /\(/, | |
| 155 | + end: /\)/, | |
| 156 | + contains: [ "self" ] // allow nested () inside our annotation | |
| 157 | + } | |
| 158 | + ] | |
| 159 | + }; | |
| 160 | + const PARAMS = { | |
| 161 | + className: 'params', | |
| 162 | + begin: /\(/, | |
| 163 | + end: /\)/, | |
| 164 | + keywords: KEYWORDS, | |
| 165 | + relevance: 0, | |
| 166 | + contains: [ hljs.C_BLOCK_COMMENT_MODE ], | |
| 167 | + endsParent: true | |
| 168 | + }; | |
| 169 | + | |
| 170 | + return { | |
| 171 | + name: 'Java', | |
| 172 | + aliases: [ 'jsp' ], | |
| 173 | + keywords: KEYWORDS, | |
| 174 | + illegal: /<\/|#/, | |
| 175 | + contains: [ | |
| 176 | + hljs.COMMENT( | |
| 177 | + '/\\*\\*', | |
| 178 | + '\\*/', | |
| 179 | + { | |
| 180 | + relevance: 0, | |
| 181 | + contains: [ | |
| 182 | + { | |
| 183 | + // eat up @'s in emails to prevent them to be recognized as doctags | |
| 184 | + begin: /\w+@/, | |
| 185 | + relevance: 0 | |
| 186 | + }, | |
| 187 | + { | |
| 188 | + className: 'doctag', | |
| 189 | + begin: '@[A-Za-z]+' | |
| 190 | + } | |
| 191 | + ] | |
| 192 | + } | |
| 193 | + ), | |
| 194 | + // relevance boost | |
| 195 | + { | |
| 196 | + begin: /import java\.[a-z]+\./, | |
| 197 | + keywords: "import", | |
| 198 | + relevance: 2 | |
| 199 | + }, | |
| 200 | + hljs.C_LINE_COMMENT_MODE, | |
| 201 | + hljs.C_BLOCK_COMMENT_MODE, | |
| 202 | + { | |
| 203 | + begin: /"""/, | |
| 204 | + end: /"""/, | |
| 205 | + className: "string", | |
| 206 | + contains: [ hljs.BACKSLASH_ESCAPE ] | |
| 207 | + }, | |
| 208 | + hljs.APOS_STRING_MODE, | |
| 209 | + hljs.QUOTE_STRING_MODE, | |
| 210 | + { | |
| 211 | + match: [ | |
| 212 | + /\b(?:class|interface|enum|extends|implements|new)/, | |
| 213 | + /\s+/, | |
| 214 | + JAVA_IDENT_RE | |
| 215 | + ], | |
| 216 | + className: { | |
| 217 | + 1: "keyword", | |
| 218 | + 3: "title.class" | |
| 219 | + } | |
| 220 | + }, | |
| 221 | + { | |
| 222 | + // Exceptions for hyphenated keywords | |
| 223 | + match: /non-sealed/, | |
| 224 | + scope: "keyword" | |
| 225 | + }, | |
| 226 | + { | |
| 227 | + begin: [ | |
| 228 | + regex.concat(/(?!else)/, JAVA_IDENT_RE), | |
| 229 | + /\s+/, | |
| 230 | + JAVA_IDENT_RE, | |
| 231 | + /\s+/, | |
| 232 | + /=(?!=)/ | |
| 233 | + ], | |
| 234 | + className: { | |
| 235 | + 1: "type", | |
| 236 | + 3: "variable", | |
| 237 | + 5: "operator" | |
| 238 | + } | |
| 239 | + }, | |
| 240 | + { | |
| 241 | + begin: [ | |
| 242 | + /record/, | |
| 243 | + /\s+/, | |
| 244 | + JAVA_IDENT_RE | |
| 245 | + ], | |
| 246 | + className: { | |
| 247 | + 1: "keyword", | |
| 248 | + 3: "title.class" | |
| 249 | + }, | |
| 250 | + contains: [ | |
| 251 | + PARAMS, | |
| 252 | + hljs.C_LINE_COMMENT_MODE, | |
| 253 | + hljs.C_BLOCK_COMMENT_MODE | |
| 254 | + ] | |
| 255 | + }, | |
| 256 | + { | |
| 257 | + // Expression keywords prevent 'keyword Name(...)' from being | |
| 258 | + // recognized as a function definition | |
| 259 | + beginKeywords: 'new throw return else', | |
| 260 | + relevance: 0 | |
| 261 | + }, | |
| 262 | + { | |
| 263 | + begin: [ | |
| 264 | + '(?:' + GENERIC_IDENT_RE + '\\s+)', | |
| 265 | + hljs.UNDERSCORE_IDENT_RE, | |
| 266 | + /\s*(?=\()/ | |
| 267 | + ], | |
| 268 | + className: { 2: "title.function" }, | |
| 269 | + keywords: KEYWORDS, | |
| 270 | + contains: [ | |
| 271 | + { | |
| 272 | + className: 'params', | |
| 273 | + begin: /\(/, | |
| 274 | + end: /\)/, | |
| 275 | + keywords: KEYWORDS, | |
| 276 | + relevance: 0, | |
| 277 | + contains: [ | |
| 278 | + ANNOTATION, | |
| 279 | + hljs.APOS_STRING_MODE, | |
| 280 | + hljs.QUOTE_STRING_MODE, | |
| 281 | + NUMERIC, | |
| 282 | + hljs.C_BLOCK_COMMENT_MODE | |
| 283 | + ] | |
| 284 | + }, | |
| 285 | + hljs.C_LINE_COMMENT_MODE, | |
| 286 | + hljs.C_BLOCK_COMMENT_MODE | |
| 287 | + ] | |
| 288 | + }, | |
| 289 | + NUMERIC, | |
| 290 | + ANNOTATION | |
| 291 | + ] | |
| 292 | + }; | |
| 293 | + } | |
| 294 | + | |
| 295 | + return java; | |
| 296 | + | |
| 297 | +})(); | |
| 298 | +; | |
| 299 | +export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/java.min.js
... | ... | @@ -0,0 +1,38 @@ |
| 1 | +/*! `java` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar=(()=>{"use strict" | |
| 3 | +;var e="[0-9](_*[0-9])*",a=`\\.(${e})`,n="[0-9a-fA-F](_*[0-9a-fA-F])*",s={ | |
| 4 | +className:"number",variants:[{ | |
| 5 | +begin:`(\\b(${e})((${a})|\\.)?|(${a}))[eE][+-]?(${e})[fFdD]?\\b`},{ | |
| 6 | +begin:`\\b(${e})((${a})[fFdD]?\\b|\\.([fFdD]\\b)?)`},{begin:`(${a})[fFdD]?\\b` | |
| 7 | +},{begin:`\\b(${e})[fFdD]\\b`},{ | |
| 8 | +begin:`\\b0[xX]((${n})\\.?|(${n})?\\.(${n}))[pP][+-]?(${e})[fFdD]?\\b`},{ | |
| 9 | +begin:"\\b(0|[1-9](_*[0-9])*)[lL]?\\b"},{begin:`\\b0[xX](${n})[lL]?\\b`},{ | |
| 10 | +begin:"\\b0(_*[0-7])*[lL]?\\b"},{begin:"\\b0[bB][01](_*[01])*[lL]?\\b"}], | |
| 11 | +relevance:0};function t(e,a,n){return-1===n?"":e.replace(a,(s=>t(e,a,n-1)))} | |
| 12 | +return e=>{ | |
| 13 | +const a=e.regex,n="[\xc0-\u02b8a-zA-Z_$][\xc0-\u02b8a-zA-Z_$0-9]*",r=n+t("(?:<"+n+"~~~(?:\\s*,\\s*"+n+"~~~)*>)?",/~~~/g,2),i={ | |
| 14 | +keyword:["synchronized","abstract","private","var","static","if","const ","for","while","strictfp","finally","protected","import","native","final","void","enum","else","break","transient","catch","instanceof","volatile","case","assert","package","default","public","try","switch","continue","throws","protected","public","private","module","requires","exports","do","sealed","yield","permits","goto","when"], | |
| 15 | +literal:["false","true","null"], | |
| 16 | +type:["char","boolean","long","float","int","byte","short","double"], | |
| 17 | +built_in:["super","this"]},l={className:"meta",begin:"@"+n,contains:[{ | |
| 18 | +begin:/\(/,end:/\)/,contains:["self"]}]},c={className:"params",begin:/\(/, | |
| 19 | +end:/\)/,keywords:i,relevance:0,contains:[e.C_BLOCK_COMMENT_MODE],endsParent:!0} | |
| 20 | +;return{name:"Java",aliases:["jsp"],keywords:i,illegal:/<\/|#/, | |
| 21 | +contains:[e.COMMENT("/\\*\\*","\\*/",{relevance:0,contains:[{begin:/\w+@/, | |
| 22 | +relevance:0},{className:"doctag",begin:"@[A-Za-z]+"}]}),{ | |
| 23 | +begin:/import java\.[a-z]+\./,keywords:"import",relevance:2 | |
| 24 | +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE,{begin:/"""/,end:/"""/, | |
| 25 | +className:"string",contains:[e.BACKSLASH_ESCAPE] | |
| 26 | +},e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,{ | |
| 27 | +match:[/\b(?:class|interface|enum|extends|implements|new)/,/\s+/,n],className:{ | |
| 28 | +1:"keyword",3:"title.class"}},{match:/non-sealed/,scope:"keyword"},{ | |
| 29 | +begin:[a.concat(/(?!else)/,n),/\s+/,n,/\s+/,/=(?!=)/],className:{1:"type", | |
| 30 | +3:"variable",5:"operator"}},{begin:[/record/,/\s+/,n],className:{1:"keyword", | |
| 31 | +3:"title.class"},contains:[c,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},{ | |
| 32 | +beginKeywords:"new throw return else",relevance:0},{ | |
| 33 | +begin:["(?:"+r+"\\s+)",e.UNDERSCORE_IDENT_RE,/\s*(?=\()/],className:{ | |
| 34 | +2:"title.function"},keywords:i,contains:[{className:"params",begin:/\(/, | |
| 35 | +end:/\)/,keywords:i,relevance:0, | |
| 36 | +contains:[l,e.APOS_STRING_MODE,e.QUOTE_STRING_MODE,s,e.C_BLOCK_COMMENT_MODE] | |
| 37 | +},e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE]},s,l]}}})() | |
| 38 | +;export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/javascript.js
... | ... | @@ -0,0 +1,777 @@ |
| 1 | +/*! `javascript` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar = (function () { | |
| 3 | + 'use strict'; | |
| 4 | + | |
| 5 | + const IDENT_RE = '[A-Za-z$_][0-9A-Za-z$_]*'; | |
| 6 | + const KEYWORDS = [ | |
| 7 | + "as", // for exports | |
| 8 | + "in", | |
| 9 | + "of", | |
| 10 | + "if", | |
| 11 | + "for", | |
| 12 | + "while", | |
| 13 | + "finally", | |
| 14 | + "var", | |
| 15 | + "new", | |
| 16 | + "function", | |
| 17 | + "do", | |
| 18 | + "return", | |
| 19 | + "void", | |
| 20 | + "else", | |
| 21 | + "break", | |
| 22 | + "catch", | |
| 23 | + "instanceof", | |
| 24 | + "with", | |
| 25 | + "throw", | |
| 26 | + "case", | |
| 27 | + "default", | |
| 28 | + "try", | |
| 29 | + "switch", | |
| 30 | + "continue", | |
| 31 | + "typeof", | |
| 32 | + "delete", | |
| 33 | + "let", | |
| 34 | + "yield", | |
| 35 | + "const", | |
| 36 | + "class", | |
| 37 | + // JS handles these with a special rule | |
| 38 | + // "get", | |
| 39 | + // "set", | |
| 40 | + "debugger", | |
| 41 | + "async", | |
| 42 | + "await", | |
| 43 | + "static", | |
| 44 | + "import", | |
| 45 | + "from", | |
| 46 | + "export", | |
| 47 | + "extends", | |
| 48 | + // It's reached stage 3, which is "recommended for implementation": | |
| 49 | + "using" | |
| 50 | + ]; | |
| 51 | + const LITERALS = [ | |
| 52 | + "true", | |
| 53 | + "false", | |
| 54 | + "null", | |
| 55 | + "undefined", | |
| 56 | + "NaN", | |
| 57 | + "Infinity" | |
| 58 | + ]; | |
| 59 | + | |
| 60 | + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects | |
| 61 | + const TYPES = [ | |
| 62 | + // Fundamental objects | |
| 63 | + "Object", | |
| 64 | + "Function", | |
| 65 | + "Boolean", | |
| 66 | + "Symbol", | |
| 67 | + // numbers and dates | |
| 68 | + "Math", | |
| 69 | + "Date", | |
| 70 | + "Number", | |
| 71 | + "BigInt", | |
| 72 | + // text | |
| 73 | + "String", | |
| 74 | + "RegExp", | |
| 75 | + // Indexed collections | |
| 76 | + "Array", | |
| 77 | + "Float32Array", | |
| 78 | + "Float64Array", | |
| 79 | + "Int8Array", | |
| 80 | + "Uint8Array", | |
| 81 | + "Uint8ClampedArray", | |
| 82 | + "Int16Array", | |
| 83 | + "Int32Array", | |
| 84 | + "Uint16Array", | |
| 85 | + "Uint32Array", | |
| 86 | + "BigInt64Array", | |
| 87 | + "BigUint64Array", | |
| 88 | + // Keyed collections | |
| 89 | + "Set", | |
| 90 | + "Map", | |
| 91 | + "WeakSet", | |
| 92 | + "WeakMap", | |
| 93 | + // Structured data | |
| 94 | + "ArrayBuffer", | |
| 95 | + "SharedArrayBuffer", | |
| 96 | + "Atomics", | |
| 97 | + "DataView", | |
| 98 | + "JSON", | |
| 99 | + // Control abstraction objects | |
| 100 | + "Promise", | |
| 101 | + "Generator", | |
| 102 | + "GeneratorFunction", | |
| 103 | + "AsyncFunction", | |
| 104 | + // Reflection | |
| 105 | + "Reflect", | |
| 106 | + "Proxy", | |
| 107 | + // Internationalization | |
| 108 | + "Intl", | |
| 109 | + // WebAssembly | |
| 110 | + "WebAssembly" | |
| 111 | + ]; | |
| 112 | + | |
| 113 | + const ERROR_TYPES = [ | |
| 114 | + "Error", | |
| 115 | + "EvalError", | |
| 116 | + "InternalError", | |
| 117 | + "RangeError", | |
| 118 | + "ReferenceError", | |
| 119 | + "SyntaxError", | |
| 120 | + "TypeError", | |
| 121 | + "URIError" | |
| 122 | + ]; | |
| 123 | + | |
| 124 | + const BUILT_IN_GLOBALS = [ | |
| 125 | + "setInterval", | |
| 126 | + "setTimeout", | |
| 127 | + "clearInterval", | |
| 128 | + "clearTimeout", | |
| 129 | + | |
| 130 | + "require", | |
| 131 | + "exports", | |
| 132 | + | |
| 133 | + "eval", | |
| 134 | + "isFinite", | |
| 135 | + "isNaN", | |
| 136 | + "parseFloat", | |
| 137 | + "parseInt", | |
| 138 | + "decodeURI", | |
| 139 | + "decodeURIComponent", | |
| 140 | + "encodeURI", | |
| 141 | + "encodeURIComponent", | |
| 142 | + "escape", | |
| 143 | + "unescape" | |
| 144 | + ]; | |
| 145 | + | |
| 146 | + const BUILT_IN_VARIABLES = [ | |
| 147 | + "arguments", | |
| 148 | + "this", | |
| 149 | + "super", | |
| 150 | + "console", | |
| 151 | + "window", | |
| 152 | + "document", | |
| 153 | + "localStorage", | |
| 154 | + "sessionStorage", | |
| 155 | + "module", | |
| 156 | + "global" // Node.js | |
| 157 | + ]; | |
| 158 | + | |
| 159 | + const BUILT_INS = [].concat( | |
| 160 | + BUILT_IN_GLOBALS, | |
| 161 | + TYPES, | |
| 162 | + ERROR_TYPES | |
| 163 | + ); | |
| 164 | + | |
| 165 | + /* | |
| 166 | + Language: JavaScript | |
| 167 | + Description: JavaScript (JS) is a lightweight, interpreted, or just-in-time compiled programming language with first-class functions. | |
| 168 | + Category: common, scripting, web | |
| 169 | + Website: https://developer.mozilla.org/en-US/docs/Web/JavaScript | |
| 170 | + */ | |
| 171 | + | |
| 172 | + | |
| 173 | + /** @type LanguageFn */ | |
| 174 | + function javascript(hljs) { | |
| 175 | + const regex = hljs.regex; | |
| 176 | + /** | |
| 177 | + * Takes a string like "<Booger" and checks to see | |
| 178 | + * if we can find a matching "</Booger" later in the | |
| 179 | + * content. | |
| 180 | + * @param {RegExpMatchArray} match | |
| 181 | + * @param {{after:number}} param1 | |
| 182 | + */ | |
| 183 | + const hasClosingTag = (match, { after }) => { | |
| 184 | + const tag = "</" + match[0].slice(1); | |
| 185 | + const pos = match.input.indexOf(tag, after); | |
| 186 | + return pos !== -1; | |
| 187 | + }; | |
| 188 | + | |
| 189 | + const IDENT_RE$1 = IDENT_RE; | |
| 190 | + const FRAGMENT = { | |
| 191 | + begin: '<>', | |
| 192 | + end: '</>' | |
| 193 | + }; | |
| 194 | + // to avoid some special cases inside isTrulyOpeningTag | |
| 195 | + const XML_SELF_CLOSING = /<[A-Za-z0-9\\._:-]+\s*\/>/; | |
| 196 | + const XML_TAG = { | |
| 197 | + begin: /<[A-Za-z0-9\\._:-]+/, | |
| 198 | + end: /\/[A-Za-z0-9\\._:-]+>|\/>/, | |
| 199 | + /** | |
| 200 | + * @param {RegExpMatchArray} match | |
| 201 | + * @param {CallbackResponse} response | |
| 202 | + */ | |
| 203 | + isTrulyOpeningTag: (match, response) => { | |
| 204 | + const afterMatchIndex = match[0].length + match.index; | |
| 205 | + const nextChar = match.input[afterMatchIndex]; | |
| 206 | + if ( | |
| 207 | + // HTML should not include another raw `<` inside a tag | |
| 208 | + // nested type? | |
| 209 | + // `<Array<Array<number>>`, etc. | |
| 210 | + nextChar === "<" || | |
| 211 | + // the , gives away that this is not HTML | |
| 212 | + // `<T, A extends keyof T, V>` | |
| 213 | + nextChar === "," | |
| 214 | + ) { | |
| 215 | + response.ignoreMatch(); | |
| 216 | + return; | |
| 217 | + } | |
| 218 | + | |
| 219 | + // `<something>` | |
| 220 | + // Quite possibly a tag, lets look for a matching closing tag... | |
| 221 | + if (nextChar === ">") { | |
| 222 | + // if we cannot find a matching closing tag, then we | |
| 223 | + // will ignore it | |
| 224 | + if (!hasClosingTag(match, { after: afterMatchIndex })) { | |
| 225 | + response.ignoreMatch(); | |
| 226 | + } | |
| 227 | + } | |
| 228 | + | |
| 229 | + // `<blah />` (self-closing) | |
| 230 | + // handled by simpleSelfClosing rule | |
| 231 | + | |
| 232 | + let m; | |
| 233 | + const afterMatch = match.input.substring(afterMatchIndex); | |
| 234 | + | |
| 235 | + // some more template typing stuff | |
| 236 | + // <T = any>(key?: string) => Modify< | |
| 237 | + if ((m = afterMatch.match(/^\s*=/))) { | |
| 238 | + response.ignoreMatch(); | |
| 239 | + return; | |
| 240 | + } | |
| 241 | + | |
| 242 | + // `<From extends string>` | |
| 243 | + // technically this could be HTML, but it smells like a type | |
| 244 | + // NOTE: This is ugh, but added specifically for https://github.com/highlightjs/highlight.js/issues/3276 | |
| 245 | + if ((m = afterMatch.match(/^\s+extends\s+/))) { | |
| 246 | + if (m.index === 0) { | |
| 247 | + response.ignoreMatch(); | |
| 248 | + // eslint-disable-next-line no-useless-return | |
| 249 | + return; | |
| 250 | + } | |
| 251 | + } | |
| 252 | + } | |
| 253 | + }; | |
| 254 | + const KEYWORDS$1 = { | |
| 255 | + $pattern: IDENT_RE, | |
| 256 | + keyword: KEYWORDS, | |
| 257 | + literal: LITERALS, | |
| 258 | + built_in: BUILT_INS, | |
| 259 | + "variable.language": BUILT_IN_VARIABLES | |
| 260 | + }; | |
| 261 | + | |
| 262 | + // https://tc39.es/ecma262/#sec-literals-numeric-literals | |
| 263 | + const decimalDigits = '[0-9](_?[0-9])*'; | |
| 264 | + const frac = `\\.(${decimalDigits})`; | |
| 265 | + // DecimalIntegerLiteral, including Annex B NonOctalDecimalIntegerLiteral | |
| 266 | + // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals | |
| 267 | + const decimalInteger = `0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*`; | |
| 268 | + const NUMBER = { | |
| 269 | + className: 'number', | |
| 270 | + variants: [ | |
| 271 | + // DecimalLiteral | |
| 272 | + { begin: `(\\b(${decimalInteger})((${frac})|\\.)?|(${frac}))` + | |
| 273 | + `[eE][+-]?(${decimalDigits})\\b` }, | |
| 274 | + { begin: `\\b(${decimalInteger})\\b((${frac})\\b|\\.)?|(${frac})\\b` }, | |
| 275 | + | |
| 276 | + // DecimalBigIntegerLiteral | |
| 277 | + { begin: `\\b(0|[1-9](_?[0-9])*)n\\b` }, | |
| 278 | + | |
| 279 | + // NonDecimalIntegerLiteral | |
| 280 | + { begin: "\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b" }, | |
| 281 | + { begin: "\\b0[bB][0-1](_?[0-1])*n?\\b" }, | |
| 282 | + { begin: "\\b0[oO][0-7](_?[0-7])*n?\\b" }, | |
| 283 | + | |
| 284 | + // LegacyOctalIntegerLiteral (does not include underscore separators) | |
| 285 | + // https://tc39.es/ecma262/#sec-additional-syntax-numeric-literals | |
| 286 | + { begin: "\\b0[0-7]+n?\\b" }, | |
| 287 | + ], | |
| 288 | + relevance: 0 | |
| 289 | + }; | |
| 290 | + | |
| 291 | + const SUBST = { | |
| 292 | + className: 'subst', | |
| 293 | + begin: '\\$\\{', | |
| 294 | + end: '\\}', | |
| 295 | + keywords: KEYWORDS$1, | |
| 296 | + contains: [] // defined later | |
| 297 | + }; | |
| 298 | + const HTML_TEMPLATE = { | |
| 299 | + begin: '\.?html`', | |
| 300 | + end: '', | |
| 301 | + starts: { | |
| 302 | + end: '`', | |
| 303 | + returnEnd: false, | |
| 304 | + contains: [ | |
| 305 | + hljs.BACKSLASH_ESCAPE, | |
| 306 | + SUBST | |
| 307 | + ], | |
| 308 | + subLanguage: 'xml' | |
| 309 | + } | |
| 310 | + }; | |
| 311 | + const CSS_TEMPLATE = { | |
| 312 | + begin: '\.?css`', | |
| 313 | + end: '', | |
| 314 | + starts: { | |
| 315 | + end: '`', | |
| 316 | + returnEnd: false, | |
| 317 | + contains: [ | |
| 318 | + hljs.BACKSLASH_ESCAPE, | |
| 319 | + SUBST | |
| 320 | + ], | |
| 321 | + subLanguage: 'css' | |
| 322 | + } | |
| 323 | + }; | |
| 324 | + const GRAPHQL_TEMPLATE = { | |
| 325 | + begin: '\.?gql`', | |
| 326 | + end: '', | |
| 327 | + starts: { | |
| 328 | + end: '`', | |
| 329 | + returnEnd: false, | |
| 330 | + contains: [ | |
| 331 | + hljs.BACKSLASH_ESCAPE, | |
| 332 | + SUBST | |
| 333 | + ], | |
| 334 | + subLanguage: 'graphql' | |
| 335 | + } | |
| 336 | + }; | |
| 337 | + const TEMPLATE_STRING = { | |
| 338 | + className: 'string', | |
| 339 | + begin: '`', | |
| 340 | + end: '`', | |
| 341 | + contains: [ | |
| 342 | + hljs.BACKSLASH_ESCAPE, | |
| 343 | + SUBST | |
| 344 | + ] | |
| 345 | + }; | |
| 346 | + const JSDOC_COMMENT = hljs.COMMENT( | |
| 347 | + /\/\*\*(?!\/)/, | |
| 348 | + '\\*/', | |
| 349 | + { | |
| 350 | + relevance: 0, | |
| 351 | + contains: [ | |
| 352 | + { | |
| 353 | + begin: '(?=@[A-Za-z]+)', | |
| 354 | + relevance: 0, | |
| 355 | + contains: [ | |
| 356 | + { | |
| 357 | + className: 'doctag', | |
| 358 | + begin: '@[A-Za-z]+' | |
| 359 | + }, | |
| 360 | + { | |
| 361 | + className: 'type', | |
| 362 | + begin: '\\{', | |
| 363 | + end: '\\}', | |
| 364 | + excludeEnd: true, | |
| 365 | + excludeBegin: true, | |
| 366 | + relevance: 0 | |
| 367 | + }, | |
| 368 | + { | |
| 369 | + className: 'variable', | |
| 370 | + begin: IDENT_RE$1 + '(?=\\s*(-)|$)', | |
| 371 | + endsParent: true, | |
| 372 | + relevance: 0 | |
| 373 | + }, | |
| 374 | + // eat spaces (not newlines) so we can find | |
| 375 | + // types or variables | |
| 376 | + { | |
| 377 | + begin: /(?=[^\n])\s/, | |
| 378 | + relevance: 0 | |
| 379 | + } | |
| 380 | + ] | |
| 381 | + } | |
| 382 | + ] | |
| 383 | + } | |
| 384 | + ); | |
| 385 | + const COMMENT = { | |
| 386 | + className: "comment", | |
| 387 | + variants: [ | |
| 388 | + JSDOC_COMMENT, | |
| 389 | + hljs.C_BLOCK_COMMENT_MODE, | |
| 390 | + hljs.C_LINE_COMMENT_MODE | |
| 391 | + ] | |
| 392 | + }; | |
| 393 | + const SUBST_INTERNALS = [ | |
| 394 | + hljs.APOS_STRING_MODE, | |
| 395 | + hljs.QUOTE_STRING_MODE, | |
| 396 | + HTML_TEMPLATE, | |
| 397 | + CSS_TEMPLATE, | |
| 398 | + GRAPHQL_TEMPLATE, | |
| 399 | + TEMPLATE_STRING, | |
| 400 | + // Skip numbers when they are part of a variable name | |
| 401 | + { match: /\$\d+/ }, | |
| 402 | + NUMBER, | |
| 403 | + // This is intentional: | |
| 404 | + // See https://github.com/highlightjs/highlight.js/issues/3288 | |
| 405 | + // hljs.REGEXP_MODE | |
| 406 | + ]; | |
| 407 | + SUBST.contains = SUBST_INTERNALS | |
| 408 | + .concat({ | |
| 409 | + // we need to pair up {} inside our subst to prevent | |
| 410 | + // it from ending too early by matching another } | |
| 411 | + begin: /\{/, | |
| 412 | + end: /\}/, | |
| 413 | + keywords: KEYWORDS$1, | |
| 414 | + contains: [ | |
| 415 | + "self" | |
| 416 | + ].concat(SUBST_INTERNALS) | |
| 417 | + }); | |
| 418 | + const SUBST_AND_COMMENTS = [].concat(COMMENT, SUBST.contains); | |
| 419 | + const PARAMS_CONTAINS = SUBST_AND_COMMENTS.concat([ | |
| 420 | + // eat recursive parens in sub expressions | |
| 421 | + { | |
| 422 | + begin: /(\s*)\(/, | |
| 423 | + end: /\)/, | |
| 424 | + keywords: KEYWORDS$1, | |
| 425 | + contains: ["self"].concat(SUBST_AND_COMMENTS) | |
| 426 | + } | |
| 427 | + ]); | |
| 428 | + const PARAMS = { | |
| 429 | + className: 'params', | |
| 430 | + // convert this to negative lookbehind in v12 | |
| 431 | + begin: /(\s*)\(/, // to match the parms with | |
| 432 | + end: /\)/, | |
| 433 | + excludeBegin: true, | |
| 434 | + excludeEnd: true, | |
| 435 | + keywords: KEYWORDS$1, | |
| 436 | + contains: PARAMS_CONTAINS | |
| 437 | + }; | |
| 438 | + | |
| 439 | + // ES6 classes | |
| 440 | + const CLASS_OR_EXTENDS = { | |
| 441 | + variants: [ | |
| 442 | + // class Car extends vehicle | |
| 443 | + { | |
| 444 | + match: [ | |
| 445 | + /class/, | |
| 446 | + /\s+/, | |
| 447 | + IDENT_RE$1, | |
| 448 | + /\s+/, | |
| 449 | + /extends/, | |
| 450 | + /\s+/, | |
| 451 | + regex.concat(IDENT_RE$1, "(", regex.concat(/\./, IDENT_RE$1), ")*") | |
| 452 | + ], | |
| 453 | + scope: { | |
| 454 | + 1: "keyword", | |
| 455 | + 3: "title.class", | |
| 456 | + 5: "keyword", | |
| 457 | + 7: "title.class.inherited" | |
| 458 | + } | |
| 459 | + }, | |
| 460 | + // class Car | |
| 461 | + { | |
| 462 | + match: [ | |
| 463 | + /class/, | |
| 464 | + /\s+/, | |
| 465 | + IDENT_RE$1 | |
| 466 | + ], | |
| 467 | + scope: { | |
| 468 | + 1: "keyword", | |
| 469 | + 3: "title.class" | |
| 470 | + } | |
| 471 | + }, | |
| 472 | + | |
| 473 | + ] | |
| 474 | + }; | |
| 475 | + | |
| 476 | + const CLASS_REFERENCE = { | |
| 477 | + relevance: 0, | |
| 478 | + match: | |
| 479 | + regex.either( | |
| 480 | + // Hard coded exceptions | |
| 481 | + /\bJSON/, | |
| 482 | + // Float32Array, OutT | |
| 483 | + /\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/, | |
| 484 | + // CSSFactory, CSSFactoryT | |
| 485 | + /\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/, | |
| 486 | + // FPs, FPsT | |
| 487 | + /\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/, | |
| 488 | + // P | |
| 489 | + // single letters are not highlighted | |
| 490 | + // BLAH | |
| 491 | + // this will be flagged as a UPPER_CASE_CONSTANT instead | |
| 492 | + ), | |
| 493 | + className: "title.class", | |
| 494 | + keywords: { | |
| 495 | + _: [ | |
| 496 | + // se we still get relevance credit for JS library classes | |
| 497 | + ...TYPES, | |
| 498 | + ...ERROR_TYPES | |
| 499 | + ] | |
| 500 | + } | |
| 501 | + }; | |
| 502 | + | |
| 503 | + const USE_STRICT = { | |
| 504 | + label: "use_strict", | |
| 505 | + className: 'meta', | |
| 506 | + relevance: 10, | |
| 507 | + begin: /^\s*['"]use (strict|asm)['"]/ | |
| 508 | + }; | |
| 509 | + | |
| 510 | + const FUNCTION_DEFINITION = { | |
| 511 | + variants: [ | |
| 512 | + { | |
| 513 | + match: [ | |
| 514 | + /function/, | |
| 515 | + /\s+/, | |
| 516 | + IDENT_RE$1, | |
| 517 | + /(?=\s*\()/ | |
| 518 | + ] | |
| 519 | + }, | |
| 520 | + // anonymous function | |
| 521 | + { | |
| 522 | + match: [ | |
| 523 | + /function/, | |
| 524 | + /\s*(?=\()/ | |
| 525 | + ] | |
| 526 | + } | |
| 527 | + ], | |
| 528 | + className: { | |
| 529 | + 1: "keyword", | |
| 530 | + 3: "title.function" | |
| 531 | + }, | |
| 532 | + label: "func.def", | |
| 533 | + contains: [ PARAMS ], | |
| 534 | + illegal: /%/ | |
| 535 | + }; | |
| 536 | + | |
| 537 | + const UPPER_CASE_CONSTANT = { | |
| 538 | + relevance: 0, | |
| 539 | + match: /\b[A-Z][A-Z_0-9]+\b/, | |
| 540 | + className: "variable.constant" | |
| 541 | + }; | |
| 542 | + | |
| 543 | + function noneOf(list) { | |
| 544 | + return regex.concat("(?!", list.join("|"), ")"); | |
| 545 | + } | |
| 546 | + | |
| 547 | + const FUNCTION_CALL = { | |
| 548 | + match: regex.concat( | |
| 549 | + /\b/, | |
| 550 | + noneOf([ | |
| 551 | + ...BUILT_IN_GLOBALS, | |
| 552 | + "super", | |
| 553 | + "import" | |
| 554 | + ].map(x => `${x}\\s*\\(`)), | |
| 555 | + IDENT_RE$1, regex.lookahead(/\s*\(/)), | |
| 556 | + className: "title.function", | |
| 557 | + relevance: 0 | |
| 558 | + }; | |
| 559 | + | |
| 560 | + const PROPERTY_ACCESS = { | |
| 561 | + begin: regex.concat(/\./, regex.lookahead( | |
| 562 | + regex.concat(IDENT_RE$1, /(?![0-9A-Za-z$_(])/) | |
| 563 | + )), | |
| 564 | + end: IDENT_RE$1, | |
| 565 | + excludeBegin: true, | |
| 566 | + keywords: "prototype", | |
| 567 | + className: "property", | |
| 568 | + relevance: 0 | |
| 569 | + }; | |
| 570 | + | |
| 571 | + const GETTER_OR_SETTER = { | |
| 572 | + match: [ | |
| 573 | + /get|set/, | |
| 574 | + /\s+/, | |
| 575 | + IDENT_RE$1, | |
| 576 | + /(?=\()/ | |
| 577 | + ], | |
| 578 | + className: { | |
| 579 | + 1: "keyword", | |
| 580 | + 3: "title.function" | |
| 581 | + }, | |
| 582 | + contains: [ | |
| 583 | + { // eat to avoid empty params | |
| 584 | + begin: /\(\)/ | |
| 585 | + }, | |
| 586 | + PARAMS | |
| 587 | + ] | |
| 588 | + }; | |
| 589 | + | |
| 590 | + const FUNC_LEAD_IN_RE = '(\\(' + | |
| 591 | + '[^()]*(\\(' + | |
| 592 | + '[^()]*(\\(' + | |
| 593 | + '[^()]*' + | |
| 594 | + '\\)[^()]*)*' + | |
| 595 | + '\\)[^()]*)*' + | |
| 596 | + '\\)|' + hljs.UNDERSCORE_IDENT_RE + ')\\s*=>'; | |
| 597 | + | |
| 598 | + const FUNCTION_VARIABLE = { | |
| 599 | + match: [ | |
| 600 | + /const|var|let/, /\s+/, | |
| 601 | + IDENT_RE$1, /\s*/, | |
| 602 | + /=\s*/, | |
| 603 | + /(async\s*)?/, // async is optional | |
| 604 | + regex.lookahead(FUNC_LEAD_IN_RE) | |
| 605 | + ], | |
| 606 | + keywords: "async", | |
| 607 | + className: { | |
| 608 | + 1: "keyword", | |
| 609 | + 3: "title.function" | |
| 610 | + }, | |
| 611 | + contains: [ | |
| 612 | + PARAMS | |
| 613 | + ] | |
| 614 | + }; | |
| 615 | + | |
| 616 | + return { | |
| 617 | + name: 'JavaScript', | |
| 618 | + aliases: ['js', 'jsx', 'mjs', 'cjs'], | |
| 619 | + keywords: KEYWORDS$1, | |
| 620 | + // this will be extended by TypeScript | |
| 621 | + exports: { PARAMS_CONTAINS, CLASS_REFERENCE }, | |
| 622 | + illegal: /#(?![$_A-z])/, | |
| 623 | + contains: [ | |
| 624 | + hljs.SHEBANG({ | |
| 625 | + label: "shebang", | |
| 626 | + binary: "node", | |
| 627 | + relevance: 5 | |
| 628 | + }), | |
| 629 | + USE_STRICT, | |
| 630 | + hljs.APOS_STRING_MODE, | |
| 631 | + hljs.QUOTE_STRING_MODE, | |
| 632 | + HTML_TEMPLATE, | |
| 633 | + CSS_TEMPLATE, | |
| 634 | + GRAPHQL_TEMPLATE, | |
| 635 | + TEMPLATE_STRING, | |
| 636 | + COMMENT, | |
| 637 | + // Skip numbers when they are part of a variable name | |
| 638 | + { match: /\$\d+/ }, | |
| 639 | + NUMBER, | |
| 640 | + CLASS_REFERENCE, | |
| 641 | + { | |
| 642 | + scope: 'attr', | |
| 643 | + match: IDENT_RE$1 + regex.lookahead(':'), | |
| 644 | + relevance: 0 | |
| 645 | + }, | |
| 646 | + FUNCTION_VARIABLE, | |
| 647 | + { // "value" container | |
| 648 | + begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*', | |
| 649 | + keywords: 'return throw case', | |
| 650 | + relevance: 0, | |
| 651 | + contains: [ | |
| 652 | + COMMENT, | |
| 653 | + hljs.REGEXP_MODE, | |
| 654 | + { | |
| 655 | + className: 'function', | |
| 656 | + // we have to count the parens to make sure we actually have the | |
| 657 | + // correct bounding ( ) before the =>. There could be any number of | |
| 658 | + // sub-expressions inside also surrounded by parens. | |
| 659 | + begin: FUNC_LEAD_IN_RE, | |
| 660 | + returnBegin: true, | |
| 661 | + end: '\\s*=>', | |
| 662 | + contains: [ | |
| 663 | + { | |
| 664 | + className: 'params', | |
| 665 | + variants: [ | |
| 666 | + { | |
| 667 | + begin: hljs.UNDERSCORE_IDENT_RE, | |
| 668 | + relevance: 0 | |
| 669 | + }, | |
| 670 | + { | |
| 671 | + className: null, | |
| 672 | + begin: /\(\s*\)/, | |
| 673 | + skip: true | |
| 674 | + }, | |
| 675 | + { | |
| 676 | + begin: /(\s*)\(/, | |
| 677 | + end: /\)/, | |
| 678 | + excludeBegin: true, | |
| 679 | + excludeEnd: true, | |
| 680 | + keywords: KEYWORDS$1, | |
| 681 | + contains: PARAMS_CONTAINS | |
| 682 | + } | |
| 683 | + ] | |
| 684 | + } | |
| 685 | + ] | |
| 686 | + }, | |
| 687 | + { // could be a comma delimited list of params to a function call | |
| 688 | + begin: /,/, | |
| 689 | + relevance: 0 | |
| 690 | + }, | |
| 691 | + { | |
| 692 | + match: /\s+/, | |
| 693 | + relevance: 0 | |
| 694 | + }, | |
| 695 | + { // JSX | |
| 696 | + variants: [ | |
| 697 | + { begin: FRAGMENT.begin, end: FRAGMENT.end }, | |
| 698 | + { match: XML_SELF_CLOSING }, | |
| 699 | + { | |
| 700 | + begin: XML_TAG.begin, | |
| 701 | + // we carefully check the opening tag to see if it truly | |
| 702 | + // is a tag and not a false positive | |
| 703 | + 'on:begin': XML_TAG.isTrulyOpeningTag, | |
| 704 | + end: XML_TAG.end | |
| 705 | + } | |
| 706 | + ], | |
| 707 | + subLanguage: 'xml', | |
| 708 | + contains: [ | |
| 709 | + { | |
| 710 | + begin: XML_TAG.begin, | |
| 711 | + end: XML_TAG.end, | |
| 712 | + skip: true, | |
| 713 | + contains: ['self'] | |
| 714 | + } | |
| 715 | + ] | |
| 716 | + } | |
| 717 | + ], | |
| 718 | + }, | |
| 719 | + FUNCTION_DEFINITION, | |
| 720 | + { | |
| 721 | + // prevent this from getting swallowed up by function | |
| 722 | + // since they appear "function like" | |
| 723 | + beginKeywords: "while if switch catch for" | |
| 724 | + }, | |
| 725 | + { | |
| 726 | + // we have to count the parens to make sure we actually have the correct | |
| 727 | + // bounding ( ). There could be any number of sub-expressions inside | |
| 728 | + // also surrounded by parens. | |
| 729 | + begin: '\\b(?!function)' + hljs.UNDERSCORE_IDENT_RE + | |
| 730 | + '\\(' + // first parens | |
| 731 | + '[^()]*(\\(' + | |
| 732 | + '[^()]*(\\(' + | |
| 733 | + '[^()]*' + | |
| 734 | + '\\)[^()]*)*' + | |
| 735 | + '\\)[^()]*)*' + | |
| 736 | + '\\)\\s*\\{', // end parens | |
| 737 | + returnBegin:true, | |
| 738 | + label: "func.def", | |
| 739 | + contains: [ | |
| 740 | + PARAMS, | |
| 741 | + hljs.inherit(hljs.TITLE_MODE, { begin: IDENT_RE$1, className: "title.function" }) | |
| 742 | + ] | |
| 743 | + }, | |
| 744 | + // catch ... so it won't trigger the property rule below | |
| 745 | + { | |
| 746 | + match: /\.\.\./, | |
| 747 | + relevance: 0 | |
| 748 | + }, | |
| 749 | + PROPERTY_ACCESS, | |
| 750 | + // hack: prevents detection of keywords in some circumstances | |
| 751 | + // .keyword() | |
| 752 | + // $keyword = x | |
| 753 | + { | |
| 754 | + match: '\\$' + IDENT_RE$1, | |
| 755 | + relevance: 0 | |
| 756 | + }, | |
| 757 | + { | |
| 758 | + match: [ /\bconstructor(?=\s*\()/ ], | |
| 759 | + className: { 1: "title.function" }, | |
| 760 | + contains: [ PARAMS ] | |
| 761 | + }, | |
| 762 | + FUNCTION_CALL, | |
| 763 | + UPPER_CASE_CONSTANT, | |
| 764 | + CLASS_OR_EXTENDS, | |
| 765 | + GETTER_OR_SETTER, | |
| 766 | + { | |
| 767 | + match: /\$[(.]/ // relevance booster for a pattern common to JS libs: `$(something)` and `$.something` | |
| 768 | + } | |
| 769 | + ] | |
| 770 | + }; | |
| 771 | + } | |
| 772 | + | |
| 773 | + return javascript; | |
| 774 | + | |
| 775 | +})(); | |
| 776 | +; | |
| 777 | +export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/javascript.min.js
... | ... | @@ -0,0 +1,81 @@ |
| 1 | +/*! `javascript` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar=(()=>{"use strict" | |
| 3 | +;const e="[A-Za-z$_][0-9A-Za-z$_]*",n=["as","in","of","if","for","while","finally","var","new","function","do","return","void","else","break","catch","instanceof","with","throw","case","default","try","switch","continue","typeof","delete","let","yield","const","class","debugger","async","await","static","import","from","export","extends","using"],a=["true","false","null","undefined","NaN","Infinity"],t=["Object","Function","Boolean","Symbol","Math","Date","Number","BigInt","String","RegExp","Array","Float32Array","Float64Array","Int8Array","Uint8Array","Uint8ClampedArray","Int16Array","Int32Array","Uint16Array","Uint32Array","BigInt64Array","BigUint64Array","Set","Map","WeakSet","WeakMap","ArrayBuffer","SharedArrayBuffer","Atomics","DataView","JSON","Promise","Generator","GeneratorFunction","AsyncFunction","Reflect","Proxy","Intl","WebAssembly"],s=["Error","EvalError","InternalError","RangeError","ReferenceError","SyntaxError","TypeError","URIError"],r=["setInterval","setTimeout","clearInterval","clearTimeout","require","exports","eval","isFinite","isNaN","parseFloat","parseInt","decodeURI","decodeURIComponent","encodeURI","encodeURIComponent","escape","unescape"],c=["arguments","this","super","console","window","document","localStorage","sessionStorage","module","global"],i=[].concat(r,t,s) | |
| 4 | +;return o=>{const l=o.regex,d=e,b={begin:/<[A-Za-z0-9\\._:-]+/, | |
| 5 | +end:/\/[A-Za-z0-9\\._:-]+>|\/>/,isTrulyOpeningTag:(e,n)=>{ | |
| 6 | +const a=e[0].length+e.index,t=e.input[a] | |
| 7 | +;if("<"===t||","===t)return void n.ignoreMatch();let s | |
| 8 | +;">"===t&&(((e,{after:n})=>{const a="</"+e[0].slice(1) | |
| 9 | +;return-1!==e.input.indexOf(a,n)})(e,{after:a})||n.ignoreMatch()) | |
| 10 | +;const r=e.input.substring(a) | |
| 11 | +;((s=r.match(/^\s*=/))||(s=r.match(/^\s+extends\s+/))&&0===s.index)&&n.ignoreMatch() | |
| 12 | +}},g={$pattern:e,keyword:n,literal:a,built_in:i,"variable.language":c | |
| 13 | +},u="[0-9](_?[0-9])*",m=`\\.(${u})`,E="0|[1-9](_?[0-9])*|0[0-7]*[89][0-9]*",A={ | |
| 14 | +className:"number",variants:[{ | |
| 15 | +begin:`(\\b(${E})((${m})|\\.)?|(${m}))[eE][+-]?(${u})\\b`},{ | |
| 16 | +begin:`\\b(${E})\\b((${m})\\b|\\.)?|(${m})\\b`},{ | |
| 17 | +begin:"\\b(0|[1-9](_?[0-9])*)n\\b"},{ | |
| 18 | +begin:"\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*n?\\b"},{ | |
| 19 | +begin:"\\b0[bB][0-1](_?[0-1])*n?\\b"},{begin:"\\b0[oO][0-7](_?[0-7])*n?\\b"},{ | |
| 20 | +begin:"\\b0[0-7]+n?\\b"}],relevance:0},y={className:"subst",begin:"\\$\\{", | |
| 21 | +end:"\\}",keywords:g,contains:[]},h={begin:".?html`",end:"",starts:{end:"`", | |
| 22 | +returnEnd:!1,contains:[o.BACKSLASH_ESCAPE,y],subLanguage:"xml"}},_={ | |
| 23 | +begin:".?css`",end:"",starts:{end:"`",returnEnd:!1, | |
| 24 | +contains:[o.BACKSLASH_ESCAPE,y],subLanguage:"css"}},N={begin:".?gql`",end:"", | |
| 25 | +starts:{end:"`",returnEnd:!1,contains:[o.BACKSLASH_ESCAPE,y], | |
| 26 | +subLanguage:"graphql"}},f={className:"string",begin:"`",end:"`", | |
| 27 | +contains:[o.BACKSLASH_ESCAPE,y]},p={className:"comment", | |
| 28 | +variants:[o.COMMENT(/\/\*\*(?!\/)/,"\\*/",{relevance:0,contains:[{ | |
| 29 | +begin:"(?=@[A-Za-z]+)",relevance:0,contains:[{className:"doctag", | |
| 30 | +begin:"@[A-Za-z]+"},{className:"type",begin:"\\{",end:"\\}",excludeEnd:!0, | |
| 31 | +excludeBegin:!0,relevance:0},{className:"variable",begin:d+"(?=\\s*(-)|$)", | |
| 32 | +endsParent:!0,relevance:0},{begin:/(?=[^\n])\s/,relevance:0}]}] | |
| 33 | +}),o.C_BLOCK_COMMENT_MODE,o.C_LINE_COMMENT_MODE] | |
| 34 | +},v=[o.APOS_STRING_MODE,o.QUOTE_STRING_MODE,h,_,N,f,{match:/\$\d+/},A] | |
| 35 | +;y.contains=v.concat({begin:/\{/,end:/\}/,keywords:g,contains:["self"].concat(v) | |
| 36 | +});const S=[].concat(p,y.contains),w=S.concat([{begin:/(\s*)\(/,end:/\)/, | |
| 37 | +keywords:g,contains:["self"].concat(S)}]),R={className:"params",begin:/(\s*)\(/, | |
| 38 | +end:/\)/,excludeBegin:!0,excludeEnd:!0,keywords:g,contains:w},O={variants:[{ | |
| 39 | +match:[/class/,/\s+/,d,/\s+/,/extends/,/\s+/,l.concat(d,"(",l.concat(/\./,d),")*")], | |
| 40 | +scope:{1:"keyword",3:"title.class",5:"keyword",7:"title.class.inherited"}},{ | |
| 41 | +match:[/class/,/\s+/,d],scope:{1:"keyword",3:"title.class"}}]},k={relevance:0, | |
| 42 | +match:l.either(/\bJSON/,/\b[A-Z][a-z]+([A-Z][a-z]*|\d)*/,/\b[A-Z]{2,}([A-Z][a-z]+|\d)+([A-Z][a-z]*)*/,/\b[A-Z]{2,}[a-z]+([A-Z][a-z]+|\d)*([A-Z][a-z]*)*/), | |
| 43 | +className:"title.class",keywords:{_:[...t,...s]}},I={variants:[{ | |
| 44 | +match:[/function/,/\s+/,d,/(?=\s*\()/]},{match:[/function/,/\s*(?=\()/]}], | |
| 45 | +className:{1:"keyword",3:"title.function"},label:"func.def",contains:[R], | |
| 46 | +illegal:/%/},x={ | |
| 47 | +match:l.concat(/\b/,(T=[...r,"super","import"].map((e=>e+"\\s*\\(")), | |
| 48 | +l.concat("(?!",T.join("|"),")")),d,l.lookahead(/\s*\(/)), | |
| 49 | +className:"title.function",relevance:0};var T;const C={ | |
| 50 | +begin:l.concat(/\./,l.lookahead(l.concat(d,/(?![0-9A-Za-z$_(])/))),end:d, | |
| 51 | +excludeBegin:!0,keywords:"prototype",className:"property",relevance:0},M={ | |
| 52 | +match:[/get|set/,/\s+/,d,/(?=\()/],className:{1:"keyword",3:"title.function"}, | |
| 53 | +contains:[{begin:/\(\)/},R] | |
| 54 | +},B="(\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)|"+o.UNDERSCORE_IDENT_RE+")\\s*=>",$={ | |
| 55 | +match:[/const|var|let/,/\s+/,d,/\s*/,/=\s*/,/(async\s*)?/,l.lookahead(B)], | |
| 56 | +keywords:"async",className:{1:"keyword",3:"title.function"},contains:[R]} | |
| 57 | +;return{name:"JavaScript",aliases:["js","jsx","mjs","cjs"],keywords:g,exports:{ | |
| 58 | +PARAMS_CONTAINS:w,CLASS_REFERENCE:k},illegal:/#(?![$_A-z])/, | |
| 59 | +contains:[o.SHEBANG({label:"shebang",binary:"node",relevance:5}),{ | |
| 60 | +label:"use_strict",className:"meta",relevance:10, | |
| 61 | +begin:/^\s*['"]use (strict|asm)['"]/ | |
| 62 | +},o.APOS_STRING_MODE,o.QUOTE_STRING_MODE,h,_,N,f,p,{match:/\$\d+/},A,k,{ | |
| 63 | +scope:"attr",match:d+l.lookahead(":"),relevance:0},$,{ | |
| 64 | +begin:"("+o.RE_STARTERS_RE+"|\\b(case|return|throw)\\b)\\s*", | |
| 65 | +keywords:"return throw case",relevance:0,contains:[p,o.REGEXP_MODE,{ | |
| 66 | +className:"function",begin:B,returnBegin:!0,end:"\\s*=>",contains:[{ | |
| 67 | +className:"params",variants:[{begin:o.UNDERSCORE_IDENT_RE,relevance:0},{ | |
| 68 | +className:null,begin:/\(\s*\)/,skip:!0},{begin:/(\s*)\(/,end:/\)/, | |
| 69 | +excludeBegin:!0,excludeEnd:!0,keywords:g,contains:w}]}]},{begin:/,/,relevance:0 | |
| 70 | +},{match:/\s+/,relevance:0},{variants:[{begin:"<>",end:"</>"},{ | |
| 71 | +match:/<[A-Za-z0-9\\._:-]+\s*\/>/},{begin:b.begin, | |
| 72 | +"on:begin":b.isTrulyOpeningTag,end:b.end}],subLanguage:"xml",contains:[{ | |
| 73 | +begin:b.begin,end:b.end,skip:!0,contains:["self"]}]}]},I,{ | |
| 74 | +beginKeywords:"while if switch catch for"},{ | |
| 75 | +begin:"\\b(?!function)"+o.UNDERSCORE_IDENT_RE+"\\([^()]*(\\([^()]*(\\([^()]*\\)[^()]*)*\\)[^()]*)*\\)\\s*\\{", | |
| 76 | +returnBegin:!0,label:"func.def",contains:[R,o.inherit(o.TITLE_MODE,{begin:d, | |
| 77 | +className:"title.function"})]},{match:/\.\.\./,relevance:0},C,{match:"\\$"+d, | |
| 78 | +relevance:0},{match:[/\bconstructor(?=\s*\()/],className:{1:"title.function"}, | |
| 79 | +contains:[R]},x,{relevance:0,match:/\b[A-Z][A-Z_0-9]+\b/, | |
| 80 | +className:"variable.constant"},O,M,{match:/\$[(.]/}]}}})() | |
| 81 | +;export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/json.js
... | ... | @@ -0,0 +1,62 @@ |
| 1 | +/*! `json` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar = (function () { | |
| 3 | + 'use strict'; | |
| 4 | + | |
| 5 | + /* | |
| 6 | + Language: JSON | |
| 7 | + Description: JSON (JavaScript Object Notation) is a lightweight data-interchange format. | |
| 8 | + Author: Ivan Sagalaev <maniac@softwaremaniacs.org> | |
| 9 | + Website: http://www.json.org | |
| 10 | + Category: common, protocols, web | |
| 11 | + */ | |
| 12 | + | |
| 13 | + function json(hljs) { | |
| 14 | + const ATTRIBUTE = { | |
| 15 | + className: 'attr', | |
| 16 | + begin: /"(\\.|[^\\"\r\n])*"(?=\s*:)/, | |
| 17 | + relevance: 1.01 | |
| 18 | + }; | |
| 19 | + const PUNCTUATION = { | |
| 20 | + match: /[{}[\],:]/, | |
| 21 | + className: "punctuation", | |
| 22 | + relevance: 0 | |
| 23 | + }; | |
| 24 | + const LITERALS = [ | |
| 25 | + "true", | |
| 26 | + "false", | |
| 27 | + "null" | |
| 28 | + ]; | |
| 29 | + // NOTE: normally we would rely on `keywords` for this but using a mode here allows us | |
| 30 | + // - to use the very tight `illegal: \S` rule later to flag any other character | |
| 31 | + // - as illegal indicating that despite looking like JSON we do not truly have | |
| 32 | + // - JSON and thus improve false-positively greatly since JSON will try and claim | |
| 33 | + // - all sorts of JSON looking stuff | |
| 34 | + const LITERALS_MODE = { | |
| 35 | + scope: "literal", | |
| 36 | + beginKeywords: LITERALS.join(" "), | |
| 37 | + }; | |
| 38 | + | |
| 39 | + return { | |
| 40 | + name: 'JSON', | |
| 41 | + aliases: ['jsonc'], | |
| 42 | + keywords:{ | |
| 43 | + literal: LITERALS, | |
| 44 | + }, | |
| 45 | + contains: [ | |
| 46 | + ATTRIBUTE, | |
| 47 | + PUNCTUATION, | |
| 48 | + hljs.QUOTE_STRING_MODE, | |
| 49 | + LITERALS_MODE, | |
| 50 | + hljs.C_NUMBER_MODE, | |
| 51 | + hljs.C_LINE_COMMENT_MODE, | |
| 52 | + hljs.C_BLOCK_COMMENT_MODE | |
| 53 | + ], | |
| 54 | + illegal: '\\S' | |
| 55 | + }; | |
| 56 | + } | |
| 57 | + | |
| 58 | + return json; | |
| 59 | + | |
| 60 | +})(); | |
| 61 | +; | |
| 62 | +export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/json.min.js
... | ... | @@ -0,0 +1,8 @@ |
| 1 | +/*! `json` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar=(()=>{"use strict";return e=>{ | |
| 3 | +const a=["true","false","null"],r={scope:"literal",beginKeywords:a.join(" ")} | |
| 4 | +;return{name:"JSON",aliases:["jsonc"],keywords:{literal:a},contains:[{ | |
| 5 | +className:"attr",begin:/"(\\.|[^\\"\r\n])*"(?=\s*:)/,relevance:1.01},{ | |
| 6 | +match:/[{}[\],:]/,className:"punctuation",relevance:0 | |
| 7 | +},e.QUOTE_STRING_MODE,r,e.C_NUMBER_MODE,e.C_LINE_COMMENT_MODE,e.C_BLOCK_COMMENT_MODE], | |
| 8 | +illegal:"\\S"}}})();export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/markdown.js
... | ... | @@ -0,0 +1,256 @@ |
| 1 | +/*! `markdown` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar = (function () { | |
| 3 | + 'use strict'; | |
| 4 | + | |
| 5 | + /* | |
| 6 | + Language: Markdown | |
| 7 | + Requires: xml.js | |
| 8 | + Author: John Crepezzi <john.crepezzi@gmail.com> | |
| 9 | + Website: https://daringfireball.net/projects/markdown/ | |
| 10 | + Category: common, markup | |
| 11 | + */ | |
| 12 | + | |
| 13 | + function markdown(hljs) { | |
| 14 | + const regex = hljs.regex; | |
| 15 | + const INLINE_HTML = { | |
| 16 | + begin: /<\/?[A-Za-z_]/, | |
| 17 | + end: '>', | |
| 18 | + subLanguage: 'xml', | |
| 19 | + relevance: 0 | |
| 20 | + }; | |
| 21 | + const HORIZONTAL_RULE = { | |
| 22 | + begin: '^[-\\*]{3,}', | |
| 23 | + end: '$' | |
| 24 | + }; | |
| 25 | + const CODE = { | |
| 26 | + className: 'code', | |
| 27 | + variants: [ | |
| 28 | + // TODO: fix to allow these to work with sublanguage also | |
| 29 | + { begin: '(`{3,})[^`](.|\\n)*?\\1`*[ ]*' }, | |
| 30 | + { begin: '(~{3,})[^~](.|\\n)*?\\1~*[ ]*' }, | |
| 31 | + // needed to allow markdown as a sublanguage to work | |
| 32 | + { | |
| 33 | + begin: '```', | |
| 34 | + end: '```+[ ]*$' | |
| 35 | + }, | |
| 36 | + { | |
| 37 | + begin: '~~~', | |
| 38 | + end: '~~~+[ ]*$' | |
| 39 | + }, | |
| 40 | + { begin: '`.+?`' }, | |
| 41 | + { | |
| 42 | + begin: '(?=^( {4}|\\t))', | |
| 43 | + // use contains to gobble up multiple lines to allow the block to be whatever size | |
| 44 | + // but only have a single open/close tag vs one per line | |
| 45 | + contains: [ | |
| 46 | + { | |
| 47 | + begin: '^( {4}|\\t)', | |
| 48 | + end: '(\\n)$' | |
| 49 | + } | |
| 50 | + ], | |
| 51 | + relevance: 0 | |
| 52 | + } | |
| 53 | + ] | |
| 54 | + }; | |
| 55 | + const LIST = { | |
| 56 | + className: 'bullet', | |
| 57 | + begin: '^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)', | |
| 58 | + end: '\\s+', | |
| 59 | + excludeEnd: true | |
| 60 | + }; | |
| 61 | + const LINK_REFERENCE = { | |
| 62 | + begin: /^\[[^\n]+\]:/, | |
| 63 | + returnBegin: true, | |
| 64 | + contains: [ | |
| 65 | + { | |
| 66 | + className: 'symbol', | |
| 67 | + begin: /\[/, | |
| 68 | + end: /\]/, | |
| 69 | + excludeBegin: true, | |
| 70 | + excludeEnd: true | |
| 71 | + }, | |
| 72 | + { | |
| 73 | + className: 'link', | |
| 74 | + begin: /:\s*/, | |
| 75 | + end: /$/, | |
| 76 | + excludeBegin: true | |
| 77 | + } | |
| 78 | + ] | |
| 79 | + }; | |
| 80 | + const URL_SCHEME = /[A-Za-z][A-Za-z0-9+.-]*/; | |
| 81 | + const LINK = { | |
| 82 | + variants: [ | |
| 83 | + // too much like nested array access in so many languages | |
| 84 | + // to have any real relevance | |
| 85 | + { | |
| 86 | + begin: /\[.+?\]\[.*?\]/, | |
| 87 | + relevance: 0 | |
| 88 | + }, | |
| 89 | + // popular internet URLs | |
| 90 | + { | |
| 91 | + begin: /\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, | |
| 92 | + relevance: 2 | |
| 93 | + }, | |
| 94 | + { | |
| 95 | + begin: regex.concat(/\[.+?\]\(/, URL_SCHEME, /:\/\/.*?\)/), | |
| 96 | + relevance: 2 | |
| 97 | + }, | |
| 98 | + // relative urls | |
| 99 | + { | |
| 100 | + begin: /\[.+?\]\([./?&#].*?\)/, | |
| 101 | + relevance: 1 | |
| 102 | + }, | |
| 103 | + // whatever else, lower relevance (might not be a link at all) | |
| 104 | + { | |
| 105 | + begin: /\[.*?\]\(.*?\)/, | |
| 106 | + relevance: 0 | |
| 107 | + } | |
| 108 | + ], | |
| 109 | + returnBegin: true, | |
| 110 | + contains: [ | |
| 111 | + { | |
| 112 | + // empty strings for alt or link text | |
| 113 | + match: /\[(?=\])/ }, | |
| 114 | + { | |
| 115 | + className: 'string', | |
| 116 | + relevance: 0, | |
| 117 | + begin: '\\[', | |
| 118 | + end: '\\]', | |
| 119 | + excludeBegin: true, | |
| 120 | + returnEnd: true | |
| 121 | + }, | |
| 122 | + { | |
| 123 | + className: 'link', | |
| 124 | + relevance: 0, | |
| 125 | + begin: '\\]\\(', | |
| 126 | + end: '\\)', | |
| 127 | + excludeBegin: true, | |
| 128 | + excludeEnd: true | |
| 129 | + }, | |
| 130 | + { | |
| 131 | + className: 'symbol', | |
| 132 | + relevance: 0, | |
| 133 | + begin: '\\]\\[', | |
| 134 | + end: '\\]', | |
| 135 | + excludeBegin: true, | |
| 136 | + excludeEnd: true | |
| 137 | + } | |
| 138 | + ] | |
| 139 | + }; | |
| 140 | + const BOLD = { | |
| 141 | + className: 'strong', | |
| 142 | + contains: [], // defined later | |
| 143 | + variants: [ | |
| 144 | + { | |
| 145 | + begin: /_{2}(?!\s)/, | |
| 146 | + end: /_{2}/ | |
| 147 | + }, | |
| 148 | + { | |
| 149 | + begin: /\*{2}(?!\s)/, | |
| 150 | + end: /\*{2}/ | |
| 151 | + } | |
| 152 | + ] | |
| 153 | + }; | |
| 154 | + const ITALIC = { | |
| 155 | + className: 'emphasis', | |
| 156 | + contains: [], // defined later | |
| 157 | + variants: [ | |
| 158 | + { | |
| 159 | + begin: /\*(?![*\s])/, | |
| 160 | + end: /\*/ | |
| 161 | + }, | |
| 162 | + { | |
| 163 | + begin: /_(?![_\s])/, | |
| 164 | + end: /_/, | |
| 165 | + relevance: 0 | |
| 166 | + } | |
| 167 | + ] | |
| 168 | + }; | |
| 169 | + | |
| 170 | + // 3 level deep nesting is not allowed because it would create confusion | |
| 171 | + // in cases like `***testing***` because where we don't know if the last | |
| 172 | + // `***` is starting a new bold/italic or finishing the last one | |
| 173 | + const BOLD_WITHOUT_ITALIC = hljs.inherit(BOLD, { contains: [] }); | |
| 174 | + const ITALIC_WITHOUT_BOLD = hljs.inherit(ITALIC, { contains: [] }); | |
| 175 | + BOLD.contains.push(ITALIC_WITHOUT_BOLD); | |
| 176 | + ITALIC.contains.push(BOLD_WITHOUT_ITALIC); | |
| 177 | + | |
| 178 | + let CONTAINABLE = [ | |
| 179 | + INLINE_HTML, | |
| 180 | + LINK | |
| 181 | + ]; | |
| 182 | + | |
| 183 | + [ | |
| 184 | + BOLD, | |
| 185 | + ITALIC, | |
| 186 | + BOLD_WITHOUT_ITALIC, | |
| 187 | + ITALIC_WITHOUT_BOLD | |
| 188 | + ].forEach(m => { | |
| 189 | + m.contains = m.contains.concat(CONTAINABLE); | |
| 190 | + }); | |
| 191 | + | |
| 192 | + CONTAINABLE = CONTAINABLE.concat(BOLD, ITALIC); | |
| 193 | + | |
| 194 | + const HEADER = { | |
| 195 | + className: 'section', | |
| 196 | + variants: [ | |
| 197 | + { | |
| 198 | + begin: '^#{1,6}', | |
| 199 | + end: '$', | |
| 200 | + contains: CONTAINABLE | |
| 201 | + }, | |
| 202 | + { | |
| 203 | + begin: '(?=^.+?\\n[=-]{2,}$)', | |
| 204 | + contains: [ | |
| 205 | + { begin: '^[=-]*$' }, | |
| 206 | + { | |
| 207 | + begin: '^', | |
| 208 | + end: "\\n", | |
| 209 | + contains: CONTAINABLE | |
| 210 | + } | |
| 211 | + ] | |
| 212 | + } | |
| 213 | + ] | |
| 214 | + }; | |
| 215 | + | |
| 216 | + const BLOCKQUOTE = { | |
| 217 | + className: 'quote', | |
| 218 | + begin: '^>\\s+', | |
| 219 | + contains: CONTAINABLE, | |
| 220 | + end: '$' | |
| 221 | + }; | |
| 222 | + | |
| 223 | + const ENTITY = { | |
| 224 | + //https://spec.commonmark.org/0.31.2/#entity-references | |
| 225 | + scope: 'literal', | |
| 226 | + match: /&([a-zA-Z0-9]+|#[0-9]{1,7}|#[Xx][0-9a-fA-F]{1,6});/ | |
| 227 | + }; | |
| 228 | + | |
| 229 | + return { | |
| 230 | + name: 'Markdown', | |
| 231 | + aliases: [ | |
| 232 | + 'md', | |
| 233 | + 'mkdown', | |
| 234 | + 'mkd' | |
| 235 | + ], | |
| 236 | + contains: [ | |
| 237 | + HEADER, | |
| 238 | + INLINE_HTML, | |
| 239 | + LIST, | |
| 240 | + BOLD, | |
| 241 | + ITALIC, | |
| 242 | + BLOCKQUOTE, | |
| 243 | + CODE, | |
| 244 | + HORIZONTAL_RULE, | |
| 245 | + LINK, | |
| 246 | + LINK_REFERENCE, | |
| 247 | + ENTITY | |
| 248 | + ] | |
| 249 | + }; | |
| 250 | + } | |
| 251 | + | |
| 252 | + return markdown; | |
| 253 | + | |
| 254 | +})(); | |
| 255 | +; | |
| 256 | +export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/markdown.min.js
... | ... | @@ -0,0 +1,32 @@ |
| 1 | +/*! `markdown` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar=(()=>{"use strict";return e=>{const n={begin:/<\/?[A-Za-z_]/, | |
| 3 | +end:">",subLanguage:"xml",relevance:0},a={variants:[{begin:/\[.+?\]\[.*?\]/, | |
| 4 | +relevance:0},{ | |
| 5 | +begin:/\[.+?\]\(((data|javascript|mailto):|(?:http|ftp)s?:\/\/).*?\)/, | |
| 6 | +relevance:2},{ | |
| 7 | +begin:e.regex.concat(/\[.+?\]\(/,/[A-Za-z][A-Za-z0-9+.-]*/,/:\/\/.*?\)/), | |
| 8 | +relevance:2},{begin:/\[.+?\]\([./?&#].*?\)/,relevance:1},{ | |
| 9 | +begin:/\[.*?\]\(.*?\)/,relevance:0}],returnBegin:!0,contains:[{match:/\[(?=\])/ | |
| 10 | +},{className:"string",relevance:0,begin:"\\[",end:"\\]",excludeBegin:!0, | |
| 11 | +returnEnd:!0},{className:"link",relevance:0,begin:"\\]\\(",end:"\\)", | |
| 12 | +excludeBegin:!0,excludeEnd:!0},{className:"symbol",relevance:0,begin:"\\]\\[", | |
| 13 | +end:"\\]",excludeBegin:!0,excludeEnd:!0}]},i={className:"strong",contains:[], | |
| 14 | +variants:[{begin:/_{2}(?!\s)/,end:/_{2}/},{begin:/\*{2}(?!\s)/,end:/\*{2}/}] | |
| 15 | +},s={className:"emphasis",contains:[],variants:[{begin:/\*(?![*\s])/,end:/\*/},{ | |
| 16 | +begin:/_(?![_\s])/,end:/_/,relevance:0}]},c=e.inherit(i,{contains:[] | |
| 17 | +}),t=e.inherit(s,{contains:[]});i.contains.push(t),s.contains.push(c) | |
| 18 | +;let l=[n,a];return[i,s,c,t].forEach((e=>{e.contains=e.contains.concat(l) | |
| 19 | +})),l=l.concat(i,s),{name:"Markdown",aliases:["md","mkdown","mkd"],contains:[{ | |
| 20 | +className:"section",variants:[{begin:"^#{1,6}",end:"$",contains:l},{ | |
| 21 | +begin:"(?=^.+?\\n[=-]{2,}$)",contains:[{begin:"^[=-]*$"},{begin:"^",end:"\\n", | |
| 22 | +contains:l}]}]},n,{className:"bullet",begin:"^[ \t]*([*+-]|(\\d+\\.))(?=\\s+)", | |
| 23 | +end:"\\s+",excludeEnd:!0},i,s,{className:"quote",begin:"^>\\s+",contains:l, | |
| 24 | +end:"$"},{className:"code",variants:[{begin:"(`{3,})[^`](.|\\n)*?\\1`*[ ]*"},{ | |
| 25 | +begin:"(~{3,})[^~](.|\\n)*?\\1~*[ ]*"},{begin:"```",end:"```+[ ]*$"},{ | |
| 26 | +begin:"~~~",end:"~~~+[ ]*$"},{begin:"`.+?`"},{begin:"(?=^( {4}|\\t))", | |
| 27 | +contains:[{begin:"^( {4}|\\t)",end:"(\\n)$"}],relevance:0}]},{ | |
| 28 | +begin:"^[-\\*]{3,}",end:"$"},a,{begin:/^\[[^\n]+\]:/,returnBegin:!0,contains:[{ | |
| 29 | +className:"symbol",begin:/\[/,end:/\]/,excludeBegin:!0,excludeEnd:!0},{ | |
| 30 | +className:"link",begin:/:\s*/,end:/$/,excludeBegin:!0}]},{scope:"literal", | |
| 31 | +match:/&([a-zA-Z0-9]+|#[0-9]{1,7}|#[Xx][0-9a-fA-F]{1,6});/}]}}})() | |
| 32 | +;export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/php.js
... | ... | @@ -0,0 +1,633 @@ |
| 1 | +/*! `php` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar = (function () { | |
| 3 | + 'use strict'; | |
| 4 | + | |
| 5 | + /* | |
| 6 | + Language: PHP | |
| 7 | + Author: Victor Karamzin <Victor.Karamzin@enterra-inc.com> | |
| 8 | + Contributors: Evgeny Stepanischev <imbolk@gmail.com>, Ivan Sagalaev <maniac@softwaremaniacs.org> | |
| 9 | + Website: https://www.php.net | |
| 10 | + Category: common | |
| 11 | + */ | |
| 12 | + | |
| 13 | + /** | |
| 14 | + * @param {HLJSApi} hljs | |
| 15 | + * @returns {LanguageDetail} | |
| 16 | + * */ | |
| 17 | + function php(hljs) { | |
| 18 | + const regex = hljs.regex; | |
| 19 | + // negative look-ahead tries to avoid matching patterns that are not | |
| 20 | + // Perl at all like $ident$, @ident@, etc. | |
| 21 | + const NOT_PERL_ETC = /(?![A-Za-z0-9])(?![$])/; | |
| 22 | + const IDENT_RE = regex.concat( | |
| 23 | + /[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/, | |
| 24 | + NOT_PERL_ETC); | |
| 25 | + // Will not detect camelCase classes | |
| 26 | + const PASCAL_CASE_CLASS_NAME_RE = regex.concat( | |
| 27 | + /(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/, | |
| 28 | + NOT_PERL_ETC); | |
| 29 | + const UPCASE_NAME_RE = regex.concat( | |
| 30 | + /[A-Z]+/, | |
| 31 | + NOT_PERL_ETC); | |
| 32 | + const VARIABLE = { | |
| 33 | + scope: 'variable', | |
| 34 | + match: '\\$+' + IDENT_RE, | |
| 35 | + }; | |
| 36 | + const PREPROCESSOR = { | |
| 37 | + scope: "meta", | |
| 38 | + variants: [ | |
| 39 | + { begin: /<\?php/, relevance: 10 }, // boost for obvious PHP | |
| 40 | + { begin: /<\?=/ }, | |
| 41 | + // less relevant per PSR-1 which says not to use short-tags | |
| 42 | + { begin: /<\?/, relevance: 0.1 }, | |
| 43 | + { begin: /\?>/ } // end php tag | |
| 44 | + ] | |
| 45 | + }; | |
| 46 | + const SUBST = { | |
| 47 | + scope: 'subst', | |
| 48 | + variants: [ | |
| 49 | + { begin: /\$\w+/ }, | |
| 50 | + { | |
| 51 | + begin: /\{\$/, | |
| 52 | + end: /\}/ | |
| 53 | + } | |
| 54 | + ] | |
| 55 | + }; | |
| 56 | + const SINGLE_QUOTED = hljs.inherit(hljs.APOS_STRING_MODE, { illegal: null, }); | |
| 57 | + const DOUBLE_QUOTED = hljs.inherit(hljs.QUOTE_STRING_MODE, { | |
| 58 | + illegal: null, | |
| 59 | + contains: hljs.QUOTE_STRING_MODE.contains.concat(SUBST), | |
| 60 | + }); | |
| 61 | + | |
| 62 | + const HEREDOC = { | |
| 63 | + begin: /<<<[ \t]*(?:(\w+)|"(\w+)")\n/, | |
| 64 | + end: /[ \t]*(\w+)\b/, | |
| 65 | + contains: hljs.QUOTE_STRING_MODE.contains.concat(SUBST), | |
| 66 | + 'on:begin': (m, resp) => { resp.data._beginMatch = m[1] || m[2]; }, | |
| 67 | + 'on:end': (m, resp) => { if (resp.data._beginMatch !== m[1]) resp.ignoreMatch(); }, | |
| 68 | + }; | |
| 69 | + | |
| 70 | + const NOWDOC = hljs.END_SAME_AS_BEGIN({ | |
| 71 | + begin: /<<<[ \t]*'(\w+)'\n/, | |
| 72 | + end: /[ \t]*(\w+)\b/, | |
| 73 | + }); | |
| 74 | + // list of valid whitespaces because non-breaking space might be part of a IDENT_RE | |
| 75 | + const WHITESPACE = '[ \t\n]'; | |
| 76 | + const STRING = { | |
| 77 | + scope: 'string', | |
| 78 | + variants: [ | |
| 79 | + DOUBLE_QUOTED, | |
| 80 | + SINGLE_QUOTED, | |
| 81 | + HEREDOC, | |
| 82 | + NOWDOC | |
| 83 | + ] | |
| 84 | + }; | |
| 85 | + const NUMBER = { | |
| 86 | + scope: 'number', | |
| 87 | + variants: [ | |
| 88 | + { begin: `\\b0[bB][01]+(?:_[01]+)*\\b` }, // Binary w/ underscore support | |
| 89 | + { begin: `\\b0[oO][0-7]+(?:_[0-7]+)*\\b` }, // Octals w/ underscore support | |
| 90 | + { begin: `\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b` }, // Hex w/ underscore support | |
| 91 | + // Decimals w/ underscore support, with optional fragments and scientific exponent (e) suffix. | |
| 92 | + { begin: `(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?` } | |
| 93 | + ], | |
| 94 | + relevance: 0 | |
| 95 | + }; | |
| 96 | + const LITERALS = [ | |
| 97 | + "false", | |
| 98 | + "null", | |
| 99 | + "true" | |
| 100 | + ]; | |
| 101 | + const KWS = [ | |
| 102 | + // Magic constants: | |
| 103 | + // <https://www.php.net/manual/en/language.constants.predefined.php> | |
| 104 | + "__CLASS__", | |
| 105 | + "__DIR__", | |
| 106 | + "__FILE__", | |
| 107 | + "__FUNCTION__", | |
| 108 | + "__COMPILER_HALT_OFFSET__", | |
| 109 | + "__LINE__", | |
| 110 | + "__METHOD__", | |
| 111 | + "__NAMESPACE__", | |
| 112 | + "__TRAIT__", | |
| 113 | + // Function that look like language construct or language construct that look like function: | |
| 114 | + // List of keywords that may not require parenthesis | |
| 115 | + "die", | |
| 116 | + "echo", | |
| 117 | + "exit", | |
| 118 | + "include", | |
| 119 | + "include_once", | |
| 120 | + "print", | |
| 121 | + "require", | |
| 122 | + "require_once", | |
| 123 | + // These are not language construct (function) but operate on the currently-executing function and can access the current symbol table | |
| 124 | + // 'compact extract func_get_arg func_get_args func_num_args get_called_class get_parent_class ' + | |
| 125 | + // Other keywords: | |
| 126 | + // <https://www.php.net/manual/en/reserved.php> | |
| 127 | + // <https://www.php.net/manual/en/language.types.type-juggling.php> | |
| 128 | + "array", | |
| 129 | + "abstract", | |
| 130 | + "and", | |
| 131 | + "as", | |
| 132 | + "binary", | |
| 133 | + "bool", | |
| 134 | + "boolean", | |
| 135 | + "break", | |
| 136 | + "callable", | |
| 137 | + "case", | |
| 138 | + "catch", | |
| 139 | + "class", | |
| 140 | + "clone", | |
| 141 | + "const", | |
| 142 | + "continue", | |
| 143 | + "declare", | |
| 144 | + "default", | |
| 145 | + "do", | |
| 146 | + "double", | |
| 147 | + "else", | |
| 148 | + "elseif", | |
| 149 | + "empty", | |
| 150 | + "enddeclare", | |
| 151 | + "endfor", | |
| 152 | + "endforeach", | |
| 153 | + "endif", | |
| 154 | + "endswitch", | |
| 155 | + "endwhile", | |
| 156 | + "enum", | |
| 157 | + "eval", | |
| 158 | + "extends", | |
| 159 | + "final", | |
| 160 | + "finally", | |
| 161 | + "float", | |
| 162 | + "for", | |
| 163 | + "foreach", | |
| 164 | + "from", | |
| 165 | + "global", | |
| 166 | + "goto", | |
| 167 | + "if", | |
| 168 | + "implements", | |
| 169 | + "instanceof", | |
| 170 | + "insteadof", | |
| 171 | + "int", | |
| 172 | + "integer", | |
| 173 | + "interface", | |
| 174 | + "isset", | |
| 175 | + "iterable", | |
| 176 | + "list", | |
| 177 | + "match|0", | |
| 178 | + "mixed", | |
| 179 | + "new", | |
| 180 | + "never", | |
| 181 | + "object", | |
| 182 | + "or", | |
| 183 | + "private", | |
| 184 | + "protected", | |
| 185 | + "public", | |
| 186 | + "readonly", | |
| 187 | + "real", | |
| 188 | + "return", | |
| 189 | + "string", | |
| 190 | + "switch", | |
| 191 | + "throw", | |
| 192 | + "trait", | |
| 193 | + "try", | |
| 194 | + "unset", | |
| 195 | + "use", | |
| 196 | + "var", | |
| 197 | + "void", | |
| 198 | + "while", | |
| 199 | + "xor", | |
| 200 | + "yield" | |
| 201 | + ]; | |
| 202 | + | |
| 203 | + const BUILT_INS = [ | |
| 204 | + // Standard PHP library: | |
| 205 | + // <https://www.php.net/manual/en/book.spl.php> | |
| 206 | + "Error|0", | |
| 207 | + "AppendIterator", | |
| 208 | + "ArgumentCountError", | |
| 209 | + "ArithmeticError", | |
| 210 | + "ArrayIterator", | |
| 211 | + "ArrayObject", | |
| 212 | + "AssertionError", | |
| 213 | + "BadFunctionCallException", | |
| 214 | + "BadMethodCallException", | |
| 215 | + "CachingIterator", | |
| 216 | + "CallbackFilterIterator", | |
| 217 | + "CompileError", | |
| 218 | + "Countable", | |
| 219 | + "DirectoryIterator", | |
| 220 | + "DivisionByZeroError", | |
| 221 | + "DomainException", | |
| 222 | + "EmptyIterator", | |
| 223 | + "ErrorException", | |
| 224 | + "Exception", | |
| 225 | + "FilesystemIterator", | |
| 226 | + "FilterIterator", | |
| 227 | + "GlobIterator", | |
| 228 | + "InfiniteIterator", | |
| 229 | + "InvalidArgumentException", | |
| 230 | + "IteratorIterator", | |
| 231 | + "LengthException", | |
| 232 | + "LimitIterator", | |
| 233 | + "LogicException", | |
| 234 | + "MultipleIterator", | |
| 235 | + "NoRewindIterator", | |
| 236 | + "OutOfBoundsException", | |
| 237 | + "OutOfRangeException", | |
| 238 | + "OuterIterator", | |
| 239 | + "OverflowException", | |
| 240 | + "ParentIterator", | |
| 241 | + "ParseError", | |
| 242 | + "RangeException", | |
| 243 | + "RecursiveArrayIterator", | |
| 244 | + "RecursiveCachingIterator", | |
| 245 | + "RecursiveCallbackFilterIterator", | |
| 246 | + "RecursiveDirectoryIterator", | |
| 247 | + "RecursiveFilterIterator", | |
| 248 | + "RecursiveIterator", | |
| 249 | + "RecursiveIteratorIterator", | |
| 250 | + "RecursiveRegexIterator", | |
| 251 | + "RecursiveTreeIterator", | |
| 252 | + "RegexIterator", | |
| 253 | + "RuntimeException", | |
| 254 | + "SeekableIterator", | |
| 255 | + "SplDoublyLinkedList", | |
| 256 | + "SplFileInfo", | |
| 257 | + "SplFileObject", | |
| 258 | + "SplFixedArray", | |
| 259 | + "SplHeap", | |
| 260 | + "SplMaxHeap", | |
| 261 | + "SplMinHeap", | |
| 262 | + "SplObjectStorage", | |
| 263 | + "SplObserver", | |
| 264 | + "SplPriorityQueue", | |
| 265 | + "SplQueue", | |
| 266 | + "SplStack", | |
| 267 | + "SplSubject", | |
| 268 | + "SplTempFileObject", | |
| 269 | + "TypeError", | |
| 270 | + "UnderflowException", | |
| 271 | + "UnexpectedValueException", | |
| 272 | + "UnhandledMatchError", | |
| 273 | + // Reserved interfaces: | |
| 274 | + // <https://www.php.net/manual/en/reserved.interfaces.php> | |
| 275 | + "ArrayAccess", | |
| 276 | + "BackedEnum", | |
| 277 | + "Closure", | |
| 278 | + "Fiber", | |
| 279 | + "Generator", | |
| 280 | + "Iterator", | |
| 281 | + "IteratorAggregate", | |
| 282 | + "Serializable", | |
| 283 | + "Stringable", | |
| 284 | + "Throwable", | |
| 285 | + "Traversable", | |
| 286 | + "UnitEnum", | |
| 287 | + "WeakReference", | |
| 288 | + "WeakMap", | |
| 289 | + // Reserved classes: | |
| 290 | + // <https://www.php.net/manual/en/reserved.classes.php> | |
| 291 | + "Directory", | |
| 292 | + "__PHP_Incomplete_Class", | |
| 293 | + "parent", | |
| 294 | + "php_user_filter", | |
| 295 | + "self", | |
| 296 | + "static", | |
| 297 | + "stdClass" | |
| 298 | + ]; | |
| 299 | + | |
| 300 | + /** Dual-case keywords | |
| 301 | + * | |
| 302 | + * ["then","FILE"] => | |
| 303 | + * ["then", "THEN", "FILE", "file"] | |
| 304 | + * | |
| 305 | + * @param {string[]} items */ | |
| 306 | + const dualCase = (items) => { | |
| 307 | + /** @type string[] */ | |
| 308 | + const result = []; | |
| 309 | + items.forEach(item => { | |
| 310 | + result.push(item); | |
| 311 | + if (item.toLowerCase() === item) { | |
| 312 | + result.push(item.toUpperCase()); | |
| 313 | + } else { | |
| 314 | + result.push(item.toLowerCase()); | |
| 315 | + } | |
| 316 | + }); | |
| 317 | + return result; | |
| 318 | + }; | |
| 319 | + | |
| 320 | + const KEYWORDS = { | |
| 321 | + keyword: KWS, | |
| 322 | + literal: dualCase(LITERALS), | |
| 323 | + built_in: BUILT_INS, | |
| 324 | + }; | |
| 325 | + | |
| 326 | + /** | |
| 327 | + * @param {string[]} items */ | |
| 328 | + const normalizeKeywords = (items) => { | |
| 329 | + return items.map(item => { | |
| 330 | + return item.replace(/\|\d+$/, ""); | |
| 331 | + }); | |
| 332 | + }; | |
| 333 | + | |
| 334 | + const CONSTRUCTOR_CALL = { variants: [ | |
| 335 | + { | |
| 336 | + match: [ | |
| 337 | + /new/, | |
| 338 | + regex.concat(WHITESPACE, "+"), | |
| 339 | + // to prevent built ins from being confused as the class constructor call | |
| 340 | + regex.concat("(?!", normalizeKeywords(BUILT_INS).join("\\b|"), "\\b)"), | |
| 341 | + PASCAL_CASE_CLASS_NAME_RE, | |
| 342 | + ], | |
| 343 | + scope: { | |
| 344 | + 1: "keyword", | |
| 345 | + 4: "title.class", | |
| 346 | + }, | |
| 347 | + } | |
| 348 | + ] }; | |
| 349 | + | |
| 350 | + const CONSTANT_REFERENCE = regex.concat(IDENT_RE, "\\b(?!\\()"); | |
| 351 | + | |
| 352 | + const LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON = { variants: [ | |
| 353 | + { | |
| 354 | + match: [ | |
| 355 | + regex.concat( | |
| 356 | + /::/, | |
| 357 | + regex.lookahead(/(?!class\b)/) | |
| 358 | + ), | |
| 359 | + CONSTANT_REFERENCE, | |
| 360 | + ], | |
| 361 | + scope: { 2: "variable.constant", }, | |
| 362 | + }, | |
| 363 | + { | |
| 364 | + match: [ | |
| 365 | + /::/, | |
| 366 | + /class/, | |
| 367 | + ], | |
| 368 | + scope: { 2: "variable.language", }, | |
| 369 | + }, | |
| 370 | + { | |
| 371 | + match: [ | |
| 372 | + PASCAL_CASE_CLASS_NAME_RE, | |
| 373 | + regex.concat( | |
| 374 | + /::/, | |
| 375 | + regex.lookahead(/(?!class\b)/) | |
| 376 | + ), | |
| 377 | + CONSTANT_REFERENCE, | |
| 378 | + ], | |
| 379 | + scope: { | |
| 380 | + 1: "title.class", | |
| 381 | + 3: "variable.constant", | |
| 382 | + }, | |
| 383 | + }, | |
| 384 | + { | |
| 385 | + match: [ | |
| 386 | + PASCAL_CASE_CLASS_NAME_RE, | |
| 387 | + regex.concat( | |
| 388 | + "::", | |
| 389 | + regex.lookahead(/(?!class\b)/) | |
| 390 | + ), | |
| 391 | + ], | |
| 392 | + scope: { 1: "title.class", }, | |
| 393 | + }, | |
| 394 | + { | |
| 395 | + match: [ | |
| 396 | + PASCAL_CASE_CLASS_NAME_RE, | |
| 397 | + /::/, | |
| 398 | + /class/, | |
| 399 | + ], | |
| 400 | + scope: { | |
| 401 | + 1: "title.class", | |
| 402 | + 3: "variable.language", | |
| 403 | + }, | |
| 404 | + } | |
| 405 | + ] }; | |
| 406 | + | |
| 407 | + const NAMED_ARGUMENT = { | |
| 408 | + scope: 'attr', | |
| 409 | + match: regex.concat(IDENT_RE, regex.lookahead(':'), regex.lookahead(/(?!::)/)), | |
| 410 | + }; | |
| 411 | + const PARAMS_MODE = { | |
| 412 | + relevance: 0, | |
| 413 | + begin: /\(/, | |
| 414 | + end: /\)/, | |
| 415 | + keywords: KEYWORDS, | |
| 416 | + contains: [ | |
| 417 | + NAMED_ARGUMENT, | |
| 418 | + VARIABLE, | |
| 419 | + LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON, | |
| 420 | + hljs.C_BLOCK_COMMENT_MODE, | |
| 421 | + STRING, | |
| 422 | + NUMBER, | |
| 423 | + CONSTRUCTOR_CALL, | |
| 424 | + ], | |
| 425 | + }; | |
| 426 | + const FUNCTION_INVOKE = { | |
| 427 | + relevance: 0, | |
| 428 | + match: [ | |
| 429 | + /\b/, | |
| 430 | + // to prevent keywords from being confused as the function title | |
| 431 | + regex.concat("(?!fn\\b|function\\b|", normalizeKeywords(KWS).join("\\b|"), "|", normalizeKeywords(BUILT_INS).join("\\b|"), "\\b)"), | |
| 432 | + IDENT_RE, | |
| 433 | + regex.concat(WHITESPACE, "*"), | |
| 434 | + regex.lookahead(/(?=\()/) | |
| 435 | + ], | |
| 436 | + scope: { 3: "title.function.invoke", }, | |
| 437 | + contains: [ PARAMS_MODE ] | |
| 438 | + }; | |
| 439 | + PARAMS_MODE.contains.push(FUNCTION_INVOKE); | |
| 440 | + | |
| 441 | + const ATTRIBUTE_CONTAINS = [ | |
| 442 | + NAMED_ARGUMENT, | |
| 443 | + LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON, | |
| 444 | + hljs.C_BLOCK_COMMENT_MODE, | |
| 445 | + STRING, | |
| 446 | + NUMBER, | |
| 447 | + CONSTRUCTOR_CALL, | |
| 448 | + ]; | |
| 449 | + | |
| 450 | + const ATTRIBUTES = { | |
| 451 | + begin: regex.concat(/#\[\s*\\?/, | |
| 452 | + regex.either( | |
| 453 | + PASCAL_CASE_CLASS_NAME_RE, | |
| 454 | + UPCASE_NAME_RE | |
| 455 | + ) | |
| 456 | + ), | |
| 457 | + beginScope: "meta", | |
| 458 | + end: /]/, | |
| 459 | + endScope: "meta", | |
| 460 | + keywords: { | |
| 461 | + literal: LITERALS, | |
| 462 | + keyword: [ | |
| 463 | + 'new', | |
| 464 | + 'array', | |
| 465 | + ] | |
| 466 | + }, | |
| 467 | + contains: [ | |
| 468 | + { | |
| 469 | + begin: /\[/, | |
| 470 | + end: /]/, | |
| 471 | + keywords: { | |
| 472 | + literal: LITERALS, | |
| 473 | + keyword: [ | |
| 474 | + 'new', | |
| 475 | + 'array', | |
| 476 | + ] | |
| 477 | + }, | |
| 478 | + contains: [ | |
| 479 | + 'self', | |
| 480 | + ...ATTRIBUTE_CONTAINS, | |
| 481 | + ] | |
| 482 | + }, | |
| 483 | + ...ATTRIBUTE_CONTAINS, | |
| 484 | + { | |
| 485 | + scope: 'meta', | |
| 486 | + variants: [ | |
| 487 | + { match: PASCAL_CASE_CLASS_NAME_RE }, | |
| 488 | + { match: UPCASE_NAME_RE } | |
| 489 | + ] | |
| 490 | + } | |
| 491 | + ] | |
| 492 | + }; | |
| 493 | + | |
| 494 | + return { | |
| 495 | + case_insensitive: false, | |
| 496 | + keywords: KEYWORDS, | |
| 497 | + contains: [ | |
| 498 | + ATTRIBUTES, | |
| 499 | + hljs.HASH_COMMENT_MODE, | |
| 500 | + hljs.COMMENT('//', '$'), | |
| 501 | + hljs.COMMENT( | |
| 502 | + '/\\*', | |
| 503 | + '\\*/', | |
| 504 | + { contains: [ | |
| 505 | + { | |
| 506 | + scope: 'doctag', | |
| 507 | + match: '@[A-Za-z]+' | |
| 508 | + } | |
| 509 | + ] } | |
| 510 | + ), | |
| 511 | + { | |
| 512 | + match: /__halt_compiler\(\);/, | |
| 513 | + keywords: '__halt_compiler', | |
| 514 | + starts: { | |
| 515 | + scope: "comment", | |
| 516 | + end: hljs.MATCH_NOTHING_RE, | |
| 517 | + contains: [ | |
| 518 | + { | |
| 519 | + match: /\?>/, | |
| 520 | + scope: "meta", | |
| 521 | + endsParent: true | |
| 522 | + } | |
| 523 | + ] | |
| 524 | + } | |
| 525 | + }, | |
| 526 | + PREPROCESSOR, | |
| 527 | + { | |
| 528 | + scope: 'variable.language', | |
| 529 | + match: /\$this\b/ | |
| 530 | + }, | |
| 531 | + VARIABLE, | |
| 532 | + FUNCTION_INVOKE, | |
| 533 | + LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON, | |
| 534 | + { | |
| 535 | + match: [ | |
| 536 | + /const/, | |
| 537 | + /\s/, | |
| 538 | + IDENT_RE, | |
| 539 | + ], | |
| 540 | + scope: { | |
| 541 | + 1: "keyword", | |
| 542 | + 3: "variable.constant", | |
| 543 | + }, | |
| 544 | + }, | |
| 545 | + CONSTRUCTOR_CALL, | |
| 546 | + { | |
| 547 | + scope: 'function', | |
| 548 | + relevance: 0, | |
| 549 | + beginKeywords: 'fn function', | |
| 550 | + end: /[;{]/, | |
| 551 | + excludeEnd: true, | |
| 552 | + illegal: '[$%\\[]', | |
| 553 | + contains: [ | |
| 554 | + { beginKeywords: 'use', }, | |
| 555 | + hljs.UNDERSCORE_TITLE_MODE, | |
| 556 | + { | |
| 557 | + begin: '=>', // No markup, just a relevance booster | |
| 558 | + endsParent: true | |
| 559 | + }, | |
| 560 | + { | |
| 561 | + scope: 'params', | |
| 562 | + begin: '\\(', | |
| 563 | + end: '\\)', | |
| 564 | + excludeBegin: true, | |
| 565 | + excludeEnd: true, | |
| 566 | + keywords: KEYWORDS, | |
| 567 | + contains: [ | |
| 568 | + 'self', | |
| 569 | + ATTRIBUTES, | |
| 570 | + VARIABLE, | |
| 571 | + LEFT_AND_RIGHT_SIDE_OF_DOUBLE_COLON, | |
| 572 | + hljs.C_BLOCK_COMMENT_MODE, | |
| 573 | + STRING, | |
| 574 | + NUMBER | |
| 575 | + ] | |
| 576 | + }, | |
| 577 | + ] | |
| 578 | + }, | |
| 579 | + { | |
| 580 | + scope: 'class', | |
| 581 | + variants: [ | |
| 582 | + { | |
| 583 | + beginKeywords: "enum", | |
| 584 | + illegal: /[($"]/ | |
| 585 | + }, | |
| 586 | + { | |
| 587 | + beginKeywords: "class interface trait", | |
| 588 | + illegal: /[:($"]/ | |
| 589 | + } | |
| 590 | + ], | |
| 591 | + relevance: 0, | |
| 592 | + end: /\{/, | |
| 593 | + excludeEnd: true, | |
| 594 | + contains: [ | |
| 595 | + { beginKeywords: 'extends implements' }, | |
| 596 | + hljs.UNDERSCORE_TITLE_MODE | |
| 597 | + ] | |
| 598 | + }, | |
| 599 | + // both use and namespace still use "old style" rules (vs multi-match) | |
| 600 | + // because the namespace name can include `\` and we still want each | |
| 601 | + // element to be treated as its own *individual* title | |
| 602 | + { | |
| 603 | + beginKeywords: 'namespace', | |
| 604 | + relevance: 0, | |
| 605 | + end: ';', | |
| 606 | + illegal: /[.']/, | |
| 607 | + contains: [ hljs.inherit(hljs.UNDERSCORE_TITLE_MODE, { scope: "title.class" }) ] | |
| 608 | + }, | |
| 609 | + { | |
| 610 | + beginKeywords: 'use', | |
| 611 | + relevance: 0, | |
| 612 | + end: ';', | |
| 613 | + contains: [ | |
| 614 | + // TODO: title.function vs title.class | |
| 615 | + { | |
| 616 | + match: /\b(as|const|function)\b/, | |
| 617 | + scope: "keyword" | |
| 618 | + }, | |
| 619 | + // TODO: could be title.class or title.function | |
| 620 | + hljs.UNDERSCORE_TITLE_MODE | |
| 621 | + ] | |
| 622 | + }, | |
| 623 | + STRING, | |
| 624 | + NUMBER, | |
| 625 | + ] | |
| 626 | + }; | |
| 627 | + } | |
| 628 | + | |
| 629 | + return php; | |
| 630 | + | |
| 631 | +})(); | |
| 632 | +; | |
| 633 | +export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/php.min.js
... | ... | @@ -0,0 +1,59 @@ |
| 1 | +/*! `php` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar=(()=>{"use strict";return e=>{ | |
| 3 | +const t=e.regex,a=/(?![A-Za-z0-9])(?![$])/,r=t.concat(/[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*/,a),n=t.concat(/(\\?[A-Z][a-z0-9_\x7f-\xff]+|\\?[A-Z]+(?=[A-Z][a-z0-9_\x7f-\xff])){1,}/,a),o=t.concat(/[A-Z]+/,a),c={ | |
| 4 | +scope:"variable",match:"\\$+"+r},i={scope:"subst",variants:[{begin:/\$\w+/},{ | |
| 5 | +begin:/\{\$/,end:/\}/}]},s=e.inherit(e.APOS_STRING_MODE,{illegal:null | |
| 6 | +}),l="[ \t\n]",d={scope:"string",variants:[e.inherit(e.QUOTE_STRING_MODE,{ | |
| 7 | +illegal:null,contains:e.QUOTE_STRING_MODE.contains.concat(i)}),s,{ | |
| 8 | +begin:/<<<[ \t]*(?:(\w+)|"(\w+)")\n/,end:/[ \t]*(\w+)\b/, | |
| 9 | +contains:e.QUOTE_STRING_MODE.contains.concat(i),"on:begin":(e,t)=>{ | |
| 10 | +t.data._beginMatch=e[1]||e[2]},"on:end":(e,t)=>{ | |
| 11 | +t.data._beginMatch!==e[1]&&t.ignoreMatch()}},e.END_SAME_AS_BEGIN({ | |
| 12 | +begin:/<<<[ \t]*'(\w+)'\n/,end:/[ \t]*(\w+)\b/})]},_={scope:"number",variants:[{ | |
| 13 | +begin:"\\b0[bB][01]+(?:_[01]+)*\\b"},{begin:"\\b0[oO][0-7]+(?:_[0-7]+)*\\b"},{ | |
| 14 | +begin:"\\b0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*\\b"},{ | |
| 15 | +begin:"(?:\\b\\d+(?:_\\d+)*(\\.(?:\\d+(?:_\\d+)*))?|\\B\\.\\d+)(?:[eE][+-]?\\d+)?" | |
| 16 | +}],relevance:0 | |
| 17 | +},p=["false","null","true"],b=["__CLASS__","__DIR__","__FILE__","__FUNCTION__","__COMPILER_HALT_OFFSET__","__LINE__","__METHOD__","__NAMESPACE__","__TRAIT__","die","echo","exit","include","include_once","print","require","require_once","array","abstract","and","as","binary","bool","boolean","break","callable","case","catch","class","clone","const","continue","declare","default","do","double","else","elseif","empty","enddeclare","endfor","endforeach","endif","endswitch","endwhile","enum","eval","extends","final","finally","float","for","foreach","from","global","goto","if","implements","instanceof","insteadof","int","integer","interface","isset","iterable","list","match|0","mixed","new","never","object","or","private","protected","public","readonly","real","return","string","switch","throw","trait","try","unset","use","var","void","while","xor","yield"],E=["Error|0","AppendIterator","ArgumentCountError","ArithmeticError","ArrayIterator","ArrayObject","AssertionError","BadFunctionCallException","BadMethodCallException","CachingIterator","CallbackFilterIterator","CompileError","Countable","DirectoryIterator","DivisionByZeroError","DomainException","EmptyIterator","ErrorException","Exception","FilesystemIterator","FilterIterator","GlobIterator","InfiniteIterator","InvalidArgumentException","IteratorIterator","LengthException","LimitIterator","LogicException","MultipleIterator","NoRewindIterator","OutOfBoundsException","OutOfRangeException","OuterIterator","OverflowException","ParentIterator","ParseError","RangeException","RecursiveArrayIterator","RecursiveCachingIterator","RecursiveCallbackFilterIterator","RecursiveDirectoryIterator","RecursiveFilterIterator","RecursiveIterator","RecursiveIteratorIterator","RecursiveRegexIterator","RecursiveTreeIterator","RegexIterator","RuntimeException","SeekableIterator","SplDoublyLinkedList","SplFileInfo","SplFileObject","SplFixedArray","SplHeap","SplMaxHeap","SplMinHeap","SplObjectStorage","SplObserver","SplPriorityQueue","SplQueue","SplStack","SplSubject","SplTempFileObject","TypeError","UnderflowException","UnexpectedValueException","UnhandledMatchError","ArrayAccess","BackedEnum","Closure","Fiber","Generator","Iterator","IteratorAggregate","Serializable","Stringable","Throwable","Traversable","UnitEnum","WeakReference","WeakMap","Directory","__PHP_Incomplete_Class","parent","php_user_filter","self","static","stdClass"],u={ | |
| 18 | +keyword:b,literal:(e=>{const t=[];return e.forEach((e=>{ | |
| 19 | +t.push(e),e.toLowerCase()===e?t.push(e.toUpperCase()):t.push(e.toLowerCase()) | |
| 20 | +})),t})(p),built_in:E},g=e=>e.map((e=>e.replace(/\|\d+$/,""))),h={variants:[{ | |
| 21 | +match:[/new/,t.concat(l,"+"),t.concat("(?!",g(E).join("\\b|"),"\\b)"),n],scope:{ | |
| 22 | +1:"keyword",4:"title.class"}}]},m=t.concat(r,"\\b(?!\\()"),f={variants:[{ | |
| 23 | +match:[t.concat(/::/,t.lookahead(/(?!class\b)/)),m],scope:{2:"variable.constant" | |
| 24 | +}},{match:[/::/,/class/],scope:{2:"variable.language"}},{ | |
| 25 | +match:[n,t.concat(/::/,t.lookahead(/(?!class\b)/)),m],scope:{1:"title.class", | |
| 26 | +3:"variable.constant"}},{match:[n,t.concat("::",t.lookahead(/(?!class\b)/))], | |
| 27 | +scope:{1:"title.class"}},{match:[n,/::/,/class/],scope:{1:"title.class", | |
| 28 | +3:"variable.language"}}]},I={scope:"attr", | |
| 29 | +match:t.concat(r,t.lookahead(":"),t.lookahead(/(?!::)/))},v={relevance:0, | |
| 30 | +begin:/\(/,end:/\)/,keywords:u,contains:[I,c,f,e.C_BLOCK_COMMENT_MODE,d,_,h] | |
| 31 | +},O={relevance:0, | |
| 32 | +match:[/\b/,t.concat("(?!fn\\b|function\\b|",g(b).join("\\b|"),"|",g(E).join("\\b|"),"\\b)"),r,t.concat(l,"*"),t.lookahead(/(?=\()/)], | |
| 33 | +scope:{3:"title.function.invoke"},contains:[v]};v.contains.push(O) | |
| 34 | +;const y=[I,f,e.C_BLOCK_COMMENT_MODE,d,_,h],w={ | |
| 35 | +begin:t.concat(/#\[\s*\\?/,t.either(n,o)),beginScope:"meta",end:/]/, | |
| 36 | +endScope:"meta",keywords:{literal:p,keyword:["new","array"]},contains:[{ | |
| 37 | +begin:/\[/,end:/]/,keywords:{literal:p,keyword:["new","array"]}, | |
| 38 | +contains:["self",...y]},...y,{scope:"meta",variants:[{match:n},{match:o}]}]} | |
| 39 | +;return{case_insensitive:!1,keywords:u, | |
| 40 | +contains:[w,e.HASH_COMMENT_MODE,e.COMMENT("//","$"),e.COMMENT("/\\*","\\*/",{ | |
| 41 | +contains:[{scope:"doctag",match:"@[A-Za-z]+"}]}),{match:/__halt_compiler\(\);/, | |
| 42 | +keywords:"__halt_compiler",starts:{scope:"comment",end:e.MATCH_NOTHING_RE, | |
| 43 | +contains:[{match:/\?>/,scope:"meta",endsParent:!0}]}},{scope:"meta",variants:[{ | |
| 44 | +begin:/<\?php/,relevance:10},{begin:/<\?=/},{begin:/<\?/,relevance:.1},{ | |
| 45 | +begin:/\?>/}]},{scope:"variable.language",match:/\$this\b/},c,O,f,{ | |
| 46 | +match:[/const/,/\s/,r],scope:{1:"keyword",3:"variable.constant"}},h,{ | |
| 47 | +scope:"function",relevance:0,beginKeywords:"fn function",end:/[;{]/, | |
| 48 | +excludeEnd:!0,illegal:"[$%\\[]",contains:[{beginKeywords:"use" | |
| 49 | +},e.UNDERSCORE_TITLE_MODE,{begin:"=>",endsParent:!0},{scope:"params", | |
| 50 | +begin:"\\(",end:"\\)",excludeBegin:!0,excludeEnd:!0,keywords:u, | |
| 51 | +contains:["self",w,c,f,e.C_BLOCK_COMMENT_MODE,d,_]}]},{scope:"class",variants:[{ | |
| 52 | +beginKeywords:"enum",illegal:/[($"]/},{beginKeywords:"class interface trait", | |
| 53 | +illegal:/[:($"]/}],relevance:0,end:/\{/,excludeEnd:!0,contains:[{ | |
| 54 | +beginKeywords:"extends implements"},e.UNDERSCORE_TITLE_MODE]},{ | |
| 55 | +beginKeywords:"namespace",relevance:0,end:";",illegal:/[.']/, | |
| 56 | +contains:[e.inherit(e.UNDERSCORE_TITLE_MODE,{scope:"title.class"})]},{ | |
| 57 | +beginKeywords:"use",relevance:0,end:";",contains:[{ | |
| 58 | +match:/\b(as|const|function)\b/,scope:"keyword"},e.UNDERSCORE_TITLE_MODE]},d,_]} | |
| 59 | +}})();export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/sql.js
... | ... | @@ -0,0 +1,701 @@ |
| 1 | +/*! `sql` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar = (function () { | |
| 3 | + 'use strict'; | |
| 4 | + | |
| 5 | + /* | |
| 6 | + Language: SQL | |
| 7 | + Website: https://en.wikipedia.org/wiki/SQL | |
| 8 | + Category: common, database | |
| 9 | + */ | |
| 10 | + | |
| 11 | + /* | |
| 12 | + | |
| 13 | + Goals: | |
| 14 | + | |
| 15 | + SQL is intended to highlight basic/common SQL keywords and expressions | |
| 16 | + | |
| 17 | + - If pretty much every single SQL server includes supports, then it's a canidate. | |
| 18 | + - It is NOT intended to include tons of vendor specific keywords (Oracle, MySQL, | |
| 19 | + PostgreSQL) although the list of data types is purposely a bit more expansive. | |
| 20 | + - For more specific SQL grammars please see: | |
| 21 | + - PostgreSQL and PL/pgSQL - core | |
| 22 | + - T-SQL - https://github.com/highlightjs/highlightjs-tsql | |
| 23 | + - sql_more (core) | |
| 24 | + | |
| 25 | + */ | |
| 26 | + | |
| 27 | + function sql(hljs) { | |
| 28 | + const regex = hljs.regex; | |
| 29 | + const COMMENT_MODE = hljs.COMMENT('--', '$'); | |
| 30 | + const STRING = { | |
| 31 | + scope: 'string', | |
| 32 | + variants: [ | |
| 33 | + { | |
| 34 | + begin: /'/, | |
| 35 | + end: /'/, | |
| 36 | + contains: [ { match: /''/ } ] | |
| 37 | + } | |
| 38 | + ] | |
| 39 | + }; | |
| 40 | + const QUOTED_IDENTIFIER = { | |
| 41 | + begin: /"/, | |
| 42 | + end: /"/, | |
| 43 | + contains: [ { match: /""/ } ] | |
| 44 | + }; | |
| 45 | + | |
| 46 | + const LITERALS = [ | |
| 47 | + "true", | |
| 48 | + "false", | |
| 49 | + // Not sure it's correct to call NULL literal, and clauses like IS [NOT] NULL look strange that way. | |
| 50 | + // "null", | |
| 51 | + "unknown" | |
| 52 | + ]; | |
| 53 | + | |
| 54 | + const MULTI_WORD_TYPES = [ | |
| 55 | + "double precision", | |
| 56 | + "large object", | |
| 57 | + "with timezone", | |
| 58 | + "without timezone" | |
| 59 | + ]; | |
| 60 | + | |
| 61 | + const TYPES = [ | |
| 62 | + 'bigint', | |
| 63 | + 'binary', | |
| 64 | + 'blob', | |
| 65 | + 'boolean', | |
| 66 | + 'char', | |
| 67 | + 'character', | |
| 68 | + 'clob', | |
| 69 | + 'date', | |
| 70 | + 'dec', | |
| 71 | + 'decfloat', | |
| 72 | + 'decimal', | |
| 73 | + 'float', | |
| 74 | + 'int', | |
| 75 | + 'integer', | |
| 76 | + 'interval', | |
| 77 | + 'nchar', | |
| 78 | + 'nclob', | |
| 79 | + 'national', | |
| 80 | + 'numeric', | |
| 81 | + 'real', | |
| 82 | + 'row', | |
| 83 | + 'smallint', | |
| 84 | + 'time', | |
| 85 | + 'timestamp', | |
| 86 | + 'varchar', | |
| 87 | + 'varying', // modifier (character varying) | |
| 88 | + 'varbinary' | |
| 89 | + ]; | |
| 90 | + | |
| 91 | + const NON_RESERVED_WORDS = [ | |
| 92 | + "add", | |
| 93 | + "asc", | |
| 94 | + "collation", | |
| 95 | + "desc", | |
| 96 | + "final", | |
| 97 | + "first", | |
| 98 | + "last", | |
| 99 | + "view" | |
| 100 | + ]; | |
| 101 | + | |
| 102 | + // https://jakewheat.github.io/sql-overview/sql-2016-foundation-grammar.html#reserved-word | |
| 103 | + const RESERVED_WORDS = [ | |
| 104 | + "abs", | |
| 105 | + "acos", | |
| 106 | + "all", | |
| 107 | + "allocate", | |
| 108 | + "alter", | |
| 109 | + "and", | |
| 110 | + "any", | |
| 111 | + "are", | |
| 112 | + "array", | |
| 113 | + "array_agg", | |
| 114 | + "array_max_cardinality", | |
| 115 | + "as", | |
| 116 | + "asensitive", | |
| 117 | + "asin", | |
| 118 | + "asymmetric", | |
| 119 | + "at", | |
| 120 | + "atan", | |
| 121 | + "atomic", | |
| 122 | + "authorization", | |
| 123 | + "avg", | |
| 124 | + "begin", | |
| 125 | + "begin_frame", | |
| 126 | + "begin_partition", | |
| 127 | + "between", | |
| 128 | + "bigint", | |
| 129 | + "binary", | |
| 130 | + "blob", | |
| 131 | + "boolean", | |
| 132 | + "both", | |
| 133 | + "by", | |
| 134 | + "call", | |
| 135 | + "called", | |
| 136 | + "cardinality", | |
| 137 | + "cascaded", | |
| 138 | + "case", | |
| 139 | + "cast", | |
| 140 | + "ceil", | |
| 141 | + "ceiling", | |
| 142 | + "char", | |
| 143 | + "char_length", | |
| 144 | + "character", | |
| 145 | + "character_length", | |
| 146 | + "check", | |
| 147 | + "classifier", | |
| 148 | + "clob", | |
| 149 | + "close", | |
| 150 | + "coalesce", | |
| 151 | + "collate", | |
| 152 | + "collect", | |
| 153 | + "column", | |
| 154 | + "commit", | |
| 155 | + "condition", | |
| 156 | + "connect", | |
| 157 | + "constraint", | |
| 158 | + "contains", | |
| 159 | + "convert", | |
| 160 | + "copy", | |
| 161 | + "corr", | |
| 162 | + "corresponding", | |
| 163 | + "cos", | |
| 164 | + "cosh", | |
| 165 | + "count", | |
| 166 | + "covar_pop", | |
| 167 | + "covar_samp", | |
| 168 | + "create", | |
| 169 | + "cross", | |
| 170 | + "cube", | |
| 171 | + "cume_dist", | |
| 172 | + "current", | |
| 173 | + "current_catalog", | |
| 174 | + "current_date", | |
| 175 | + "current_default_transform_group", | |
| 176 | + "current_path", | |
| 177 | + "current_role", | |
| 178 | + "current_row", | |
| 179 | + "current_schema", | |
| 180 | + "current_time", | |
| 181 | + "current_timestamp", | |
| 182 | + "current_path", | |
| 183 | + "current_role", | |
| 184 | + "current_transform_group_for_type", | |
| 185 | + "current_user", | |
| 186 | + "cursor", | |
| 187 | + "cycle", | |
| 188 | + "date", | |
| 189 | + "day", | |
| 190 | + "deallocate", | |
| 191 | + "dec", | |
| 192 | + "decimal", | |
| 193 | + "decfloat", | |
| 194 | + "declare", | |
| 195 | + "default", | |
| 196 | + "define", | |
| 197 | + "delete", | |
| 198 | + "dense_rank", | |
| 199 | + "deref", | |
| 200 | + "describe", | |
| 201 | + "deterministic", | |
| 202 | + "disconnect", | |
| 203 | + "distinct", | |
| 204 | + "double", | |
| 205 | + "drop", | |
| 206 | + "dynamic", | |
| 207 | + "each", | |
| 208 | + "element", | |
| 209 | + "else", | |
| 210 | + "empty", | |
| 211 | + "end", | |
| 212 | + "end_frame", | |
| 213 | + "end_partition", | |
| 214 | + "end-exec", | |
| 215 | + "equals", | |
| 216 | + "escape", | |
| 217 | + "every", | |
| 218 | + "except", | |
| 219 | + "exec", | |
| 220 | + "execute", | |
| 221 | + "exists", | |
| 222 | + "exp", | |
| 223 | + "external", | |
| 224 | + "extract", | |
| 225 | + "false", | |
| 226 | + "fetch", | |
| 227 | + "filter", | |
| 228 | + "first_value", | |
| 229 | + "float", | |
| 230 | + "floor", | |
| 231 | + "for", | |
| 232 | + "foreign", | |
| 233 | + "frame_row", | |
| 234 | + "free", | |
| 235 | + "from", | |
| 236 | + "full", | |
| 237 | + "function", | |
| 238 | + "fusion", | |
| 239 | + "get", | |
| 240 | + "global", | |
| 241 | + "grant", | |
| 242 | + "group", | |
| 243 | + "grouping", | |
| 244 | + "groups", | |
| 245 | + "having", | |
| 246 | + "hold", | |
| 247 | + "hour", | |
| 248 | + "identity", | |
| 249 | + "in", | |
| 250 | + "indicator", | |
| 251 | + "initial", | |
| 252 | + "inner", | |
| 253 | + "inout", | |
| 254 | + "insensitive", | |
| 255 | + "insert", | |
| 256 | + "int", | |
| 257 | + "integer", | |
| 258 | + "intersect", | |
| 259 | + "intersection", | |
| 260 | + "interval", | |
| 261 | + "into", | |
| 262 | + "is", | |
| 263 | + "join", | |
| 264 | + "json_array", | |
| 265 | + "json_arrayagg", | |
| 266 | + "json_exists", | |
| 267 | + "json_object", | |
| 268 | + "json_objectagg", | |
| 269 | + "json_query", | |
| 270 | + "json_table", | |
| 271 | + "json_table_primitive", | |
| 272 | + "json_value", | |
| 273 | + "lag", | |
| 274 | + "language", | |
| 275 | + "large", | |
| 276 | + "last_value", | |
| 277 | + "lateral", | |
| 278 | + "lead", | |
| 279 | + "leading", | |
| 280 | + "left", | |
| 281 | + "like", | |
| 282 | + "like_regex", | |
| 283 | + "listagg", | |
| 284 | + "ln", | |
| 285 | + "local", | |
| 286 | + "localtime", | |
| 287 | + "localtimestamp", | |
| 288 | + "log", | |
| 289 | + "log10", | |
| 290 | + "lower", | |
| 291 | + "match", | |
| 292 | + "match_number", | |
| 293 | + "match_recognize", | |
| 294 | + "matches", | |
| 295 | + "max", | |
| 296 | + "member", | |
| 297 | + "merge", | |
| 298 | + "method", | |
| 299 | + "min", | |
| 300 | + "minute", | |
| 301 | + "mod", | |
| 302 | + "modifies", | |
| 303 | + "module", | |
| 304 | + "month", | |
| 305 | + "multiset", | |
| 306 | + "national", | |
| 307 | + "natural", | |
| 308 | + "nchar", | |
| 309 | + "nclob", | |
| 310 | + "new", | |
| 311 | + "no", | |
| 312 | + "none", | |
| 313 | + "normalize", | |
| 314 | + "not", | |
| 315 | + "nth_value", | |
| 316 | + "ntile", | |
| 317 | + "null", | |
| 318 | + "nullif", | |
| 319 | + "numeric", | |
| 320 | + "octet_length", | |
| 321 | + "occurrences_regex", | |
| 322 | + "of", | |
| 323 | + "offset", | |
| 324 | + "old", | |
| 325 | + "omit", | |
| 326 | + "on", | |
| 327 | + "one", | |
| 328 | + "only", | |
| 329 | + "open", | |
| 330 | + "or", | |
| 331 | + "order", | |
| 332 | + "out", | |
| 333 | + "outer", | |
| 334 | + "over", | |
| 335 | + "overlaps", | |
| 336 | + "overlay", | |
| 337 | + "parameter", | |
| 338 | + "partition", | |
| 339 | + "pattern", | |
| 340 | + "per", | |
| 341 | + "percent", | |
| 342 | + "percent_rank", | |
| 343 | + "percentile_cont", | |
| 344 | + "percentile_disc", | |
| 345 | + "period", | |
| 346 | + "portion", | |
| 347 | + "position", | |
| 348 | + "position_regex", | |
| 349 | + "power", | |
| 350 | + "precedes", | |
| 351 | + "precision", | |
| 352 | + "prepare", | |
| 353 | + "primary", | |
| 354 | + "procedure", | |
| 355 | + "ptf", | |
| 356 | + "range", | |
| 357 | + "rank", | |
| 358 | + "reads", | |
| 359 | + "real", | |
| 360 | + "recursive", | |
| 361 | + "ref", | |
| 362 | + "references", | |
| 363 | + "referencing", | |
| 364 | + "regr_avgx", | |
| 365 | + "regr_avgy", | |
| 366 | + "regr_count", | |
| 367 | + "regr_intercept", | |
| 368 | + "regr_r2", | |
| 369 | + "regr_slope", | |
| 370 | + "regr_sxx", | |
| 371 | + "regr_sxy", | |
| 372 | + "regr_syy", | |
| 373 | + "release", | |
| 374 | + "result", | |
| 375 | + "return", | |
| 376 | + "returns", | |
| 377 | + "revoke", | |
| 378 | + "right", | |
| 379 | + "rollback", | |
| 380 | + "rollup", | |
| 381 | + "row", | |
| 382 | + "row_number", | |
| 383 | + "rows", | |
| 384 | + "running", | |
| 385 | + "savepoint", | |
| 386 | + "scope", | |
| 387 | + "scroll", | |
| 388 | + "search", | |
| 389 | + "second", | |
| 390 | + "seek", | |
| 391 | + "select", | |
| 392 | + "sensitive", | |
| 393 | + "session_user", | |
| 394 | + "set", | |
| 395 | + "show", | |
| 396 | + "similar", | |
| 397 | + "sin", | |
| 398 | + "sinh", | |
| 399 | + "skip", | |
| 400 | + "smallint", | |
| 401 | + "some", | |
| 402 | + "specific", | |
| 403 | + "specifictype", | |
| 404 | + "sql", | |
| 405 | + "sqlexception", | |
| 406 | + "sqlstate", | |
| 407 | + "sqlwarning", | |
| 408 | + "sqrt", | |
| 409 | + "start", | |
| 410 | + "static", | |
| 411 | + "stddev_pop", | |
| 412 | + "stddev_samp", | |
| 413 | + "submultiset", | |
| 414 | + "subset", | |
| 415 | + "substring", | |
| 416 | + "substring_regex", | |
| 417 | + "succeeds", | |
| 418 | + "sum", | |
| 419 | + "symmetric", | |
| 420 | + "system", | |
| 421 | + "system_time", | |
| 422 | + "system_user", | |
| 423 | + "table", | |
| 424 | + "tablesample", | |
| 425 | + "tan", | |
| 426 | + "tanh", | |
| 427 | + "then", | |
| 428 | + "time", | |
| 429 | + "timestamp", | |
| 430 | + "timezone_hour", | |
| 431 | + "timezone_minute", | |
| 432 | + "to", | |
| 433 | + "trailing", | |
| 434 | + "translate", | |
| 435 | + "translate_regex", | |
| 436 | + "translation", | |
| 437 | + "treat", | |
| 438 | + "trigger", | |
| 439 | + "trim", | |
| 440 | + "trim_array", | |
| 441 | + "true", | |
| 442 | + "truncate", | |
| 443 | + "uescape", | |
| 444 | + "union", | |
| 445 | + "unique", | |
| 446 | + "unknown", | |
| 447 | + "unnest", | |
| 448 | + "update", | |
| 449 | + "upper", | |
| 450 | + "user", | |
| 451 | + "using", | |
| 452 | + "value", | |
| 453 | + "values", | |
| 454 | + "value_of", | |
| 455 | + "var_pop", | |
| 456 | + "var_samp", | |
| 457 | + "varbinary", | |
| 458 | + "varchar", | |
| 459 | + "varying", | |
| 460 | + "versioning", | |
| 461 | + "when", | |
| 462 | + "whenever", | |
| 463 | + "where", | |
| 464 | + "width_bucket", | |
| 465 | + "window", | |
| 466 | + "with", | |
| 467 | + "within", | |
| 468 | + "without", | |
| 469 | + "year", | |
| 470 | + ]; | |
| 471 | + | |
| 472 | + // these are reserved words we have identified to be functions | |
| 473 | + // and should only be highlighted in a dispatch-like context | |
| 474 | + // ie, array_agg(...), etc. | |
| 475 | + const RESERVED_FUNCTIONS = [ | |
| 476 | + "abs", | |
| 477 | + "acos", | |
| 478 | + "array_agg", | |
| 479 | + "asin", | |
| 480 | + "atan", | |
| 481 | + "avg", | |
| 482 | + "cast", | |
| 483 | + "ceil", | |
| 484 | + "ceiling", | |
| 485 | + "coalesce", | |
| 486 | + "corr", | |
| 487 | + "cos", | |
| 488 | + "cosh", | |
| 489 | + "count", | |
| 490 | + "covar_pop", | |
| 491 | + "covar_samp", | |
| 492 | + "cume_dist", | |
| 493 | + "dense_rank", | |
| 494 | + "deref", | |
| 495 | + "element", | |
| 496 | + "exp", | |
| 497 | + "extract", | |
| 498 | + "first_value", | |
| 499 | + "floor", | |
| 500 | + "json_array", | |
| 501 | + "json_arrayagg", | |
| 502 | + "json_exists", | |
| 503 | + "json_object", | |
| 504 | + "json_objectagg", | |
| 505 | + "json_query", | |
| 506 | + "json_table", | |
| 507 | + "json_table_primitive", | |
| 508 | + "json_value", | |
| 509 | + "lag", | |
| 510 | + "last_value", | |
| 511 | + "lead", | |
| 512 | + "listagg", | |
| 513 | + "ln", | |
| 514 | + "log", | |
| 515 | + "log10", | |
| 516 | + "lower", | |
| 517 | + "max", | |
| 518 | + "min", | |
| 519 | + "mod", | |
| 520 | + "nth_value", | |
| 521 | + "ntile", | |
| 522 | + "nullif", | |
| 523 | + "percent_rank", | |
| 524 | + "percentile_cont", | |
| 525 | + "percentile_disc", | |
| 526 | + "position", | |
| 527 | + "position_regex", | |
| 528 | + "power", | |
| 529 | + "rank", | |
| 530 | + "regr_avgx", | |
| 531 | + "regr_avgy", | |
| 532 | + "regr_count", | |
| 533 | + "regr_intercept", | |
| 534 | + "regr_r2", | |
| 535 | + "regr_slope", | |
| 536 | + "regr_sxx", | |
| 537 | + "regr_sxy", | |
| 538 | + "regr_syy", | |
| 539 | + "row_number", | |
| 540 | + "sin", | |
| 541 | + "sinh", | |
| 542 | + "sqrt", | |
| 543 | + "stddev_pop", | |
| 544 | + "stddev_samp", | |
| 545 | + "substring", | |
| 546 | + "substring_regex", | |
| 547 | + "sum", | |
| 548 | + "tan", | |
| 549 | + "tanh", | |
| 550 | + "translate", | |
| 551 | + "translate_regex", | |
| 552 | + "treat", | |
| 553 | + "trim", | |
| 554 | + "trim_array", | |
| 555 | + "unnest", | |
| 556 | + "upper", | |
| 557 | + "value_of", | |
| 558 | + "var_pop", | |
| 559 | + "var_samp", | |
| 560 | + "width_bucket", | |
| 561 | + ]; | |
| 562 | + | |
| 563 | + // these functions can | |
| 564 | + const POSSIBLE_WITHOUT_PARENS = [ | |
| 565 | + "current_catalog", | |
| 566 | + "current_date", | |
| 567 | + "current_default_transform_group", | |
| 568 | + "current_path", | |
| 569 | + "current_role", | |
| 570 | + "current_schema", | |
| 571 | + "current_transform_group_for_type", | |
| 572 | + "current_user", | |
| 573 | + "session_user", | |
| 574 | + "system_time", | |
| 575 | + "system_user", | |
| 576 | + "current_time", | |
| 577 | + "localtime", | |
| 578 | + "current_timestamp", | |
| 579 | + "localtimestamp" | |
| 580 | + ]; | |
| 581 | + | |
| 582 | + // those exist to boost relevance making these very | |
| 583 | + // "SQL like" keyword combos worth +1 extra relevance | |
| 584 | + const COMBOS = [ | |
| 585 | + "create table", | |
| 586 | + "insert into", | |
| 587 | + "primary key", | |
| 588 | + "foreign key", | |
| 589 | + "not null", | |
| 590 | + "alter table", | |
| 591 | + "add constraint", | |
| 592 | + "grouping sets", | |
| 593 | + "on overflow", | |
| 594 | + "character set", | |
| 595 | + "respect nulls", | |
| 596 | + "ignore nulls", | |
| 597 | + "nulls first", | |
| 598 | + "nulls last", | |
| 599 | + "depth first", | |
| 600 | + "breadth first" | |
| 601 | + ]; | |
| 602 | + | |
| 603 | + const FUNCTIONS = RESERVED_FUNCTIONS; | |
| 604 | + | |
| 605 | + const KEYWORDS = [ | |
| 606 | + ...RESERVED_WORDS, | |
| 607 | + ...NON_RESERVED_WORDS | |
| 608 | + ].filter((keyword) => { | |
| 609 | + return !RESERVED_FUNCTIONS.includes(keyword); | |
| 610 | + }); | |
| 611 | + | |
| 612 | + const VARIABLE = { | |
| 613 | + scope: "variable", | |
| 614 | + match: /@[a-z0-9][a-z0-9_]*/, | |
| 615 | + }; | |
| 616 | + | |
| 617 | + const OPERATOR = { | |
| 618 | + scope: "operator", | |
| 619 | + match: /[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/, | |
| 620 | + relevance: 0, | |
| 621 | + }; | |
| 622 | + | |
| 623 | + const FUNCTION_CALL = { | |
| 624 | + match: regex.concat(/\b/, regex.either(...FUNCTIONS), /\s*\(/), | |
| 625 | + relevance: 0, | |
| 626 | + keywords: { built_in: FUNCTIONS } | |
| 627 | + }; | |
| 628 | + | |
| 629 | + // turns a multi-word keyword combo into a regex that doesn't | |
| 630 | + // care about extra whitespace etc. | |
| 631 | + // input: "START QUERY" | |
| 632 | + // output: /\bSTART\s+QUERY\b/ | |
| 633 | + function kws_to_regex(list) { | |
| 634 | + return regex.concat( | |
| 635 | + /\b/, | |
| 636 | + regex.either(...list.map((kw) => { | |
| 637 | + return kw.replace(/\s+/, "\\s+") | |
| 638 | + })), | |
| 639 | + /\b/ | |
| 640 | + ) | |
| 641 | + } | |
| 642 | + | |
| 643 | + const MULTI_WORD_KEYWORDS = { | |
| 644 | + scope: "keyword", | |
| 645 | + match: kws_to_regex(COMBOS), | |
| 646 | + relevance: 0, | |
| 647 | + }; | |
| 648 | + | |
| 649 | + // keywords with less than 3 letters are reduced in relevancy | |
| 650 | + function reduceRelevancy(list, { | |
| 651 | + exceptions, when | |
| 652 | + } = {}) { | |
| 653 | + const qualifyFn = when; | |
| 654 | + exceptions = exceptions || []; | |
| 655 | + return list.map((item) => { | |
| 656 | + if (item.match(/\|\d+$/) || exceptions.includes(item)) { | |
| 657 | + return item; | |
| 658 | + } else if (qualifyFn(item)) { | |
| 659 | + return `${item}|0`; | |
| 660 | + } else { | |
| 661 | + return item; | |
| 662 | + } | |
| 663 | + }); | |
| 664 | + } | |
| 665 | + | |
| 666 | + return { | |
| 667 | + name: 'SQL', | |
| 668 | + case_insensitive: true, | |
| 669 | + // does not include {} or HTML tags `</` | |
| 670 | + illegal: /[{}]|<\//, | |
| 671 | + keywords: { | |
| 672 | + $pattern: /\b[\w\.]+/, | |
| 673 | + keyword: | |
| 674 | + reduceRelevancy(KEYWORDS, { when: (x) => x.length < 3 }), | |
| 675 | + literal: LITERALS, | |
| 676 | + type: TYPES, | |
| 677 | + built_in: POSSIBLE_WITHOUT_PARENS | |
| 678 | + }, | |
| 679 | + contains: [ | |
| 680 | + { | |
| 681 | + scope: "type", | |
| 682 | + match: kws_to_regex(MULTI_WORD_TYPES) | |
| 683 | + }, | |
| 684 | + MULTI_WORD_KEYWORDS, | |
| 685 | + FUNCTION_CALL, | |
| 686 | + VARIABLE, | |
| 687 | + STRING, | |
| 688 | + QUOTED_IDENTIFIER, | |
| 689 | + hljs.C_NUMBER_MODE, | |
| 690 | + hljs.C_BLOCK_COMMENT_MODE, | |
| 691 | + COMMENT_MODE, | |
| 692 | + OPERATOR | |
| 693 | + ] | |
| 694 | + }; | |
| 695 | + } | |
| 696 | + | |
| 697 | + return sql; | |
| 698 | + | |
| 699 | +})(); | |
| 700 | +; | |
| 701 | +export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/sql.min.js
... | ... | @@ -0,0 +1,21 @@ |
| 1 | +/*! `sql` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar=(()=>{"use strict";return e=>{ | |
| 3 | +const r=e.regex,t=e.COMMENT("--","$"),a=["abs","acos","array_agg","asin","atan","avg","cast","ceil","ceiling","coalesce","corr","cos","cosh","count","covar_pop","covar_samp","cume_dist","dense_rank","deref","element","exp","extract","first_value","floor","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","last_value","lead","listagg","ln","log","log10","lower","max","min","mod","nth_value","ntile","nullif","percent_rank","percentile_cont","percentile_disc","position","position_regex","power","rank","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","row_number","sin","sinh","sqrt","stddev_pop","stddev_samp","substring","substring_regex","sum","tan","tanh","translate","translate_regex","treat","trim","trim_array","unnest","upper","value_of","var_pop","var_samp","width_bucket"],n=a,s=["abs","acos","all","allocate","alter","and","any","are","array","array_agg","array_max_cardinality","as","asensitive","asin","asymmetric","at","atan","atomic","authorization","avg","begin","begin_frame","begin_partition","between","bigint","binary","blob","boolean","both","by","call","called","cardinality","cascaded","case","cast","ceil","ceiling","char","char_length","character","character_length","check","classifier","clob","close","coalesce","collate","collect","column","commit","condition","connect","constraint","contains","convert","copy","corr","corresponding","cos","cosh","count","covar_pop","covar_samp","create","cross","cube","cume_dist","current","current_catalog","current_date","current_default_transform_group","current_path","current_role","current_row","current_schema","current_time","current_timestamp","current_path","current_role","current_transform_group_for_type","current_user","cursor","cycle","date","day","deallocate","dec","decimal","decfloat","declare","default","define","delete","dense_rank","deref","describe","deterministic","disconnect","distinct","double","drop","dynamic","each","element","else","empty","end","end_frame","end_partition","end-exec","equals","escape","every","except","exec","execute","exists","exp","external","extract","false","fetch","filter","first_value","float","floor","for","foreign","frame_row","free","from","full","function","fusion","get","global","grant","group","grouping","groups","having","hold","hour","identity","in","indicator","initial","inner","inout","insensitive","insert","int","integer","intersect","intersection","interval","into","is","join","json_array","json_arrayagg","json_exists","json_object","json_objectagg","json_query","json_table","json_table_primitive","json_value","lag","language","large","last_value","lateral","lead","leading","left","like","like_regex","listagg","ln","local","localtime","localtimestamp","log","log10","lower","match","match_number","match_recognize","matches","max","member","merge","method","min","minute","mod","modifies","module","month","multiset","national","natural","nchar","nclob","new","no","none","normalize","not","nth_value","ntile","null","nullif","numeric","octet_length","occurrences_regex","of","offset","old","omit","on","one","only","open","or","order","out","outer","over","overlaps","overlay","parameter","partition","pattern","per","percent","percent_rank","percentile_cont","percentile_disc","period","portion","position","position_regex","power","precedes","precision","prepare","primary","procedure","ptf","range","rank","reads","real","recursive","ref","references","referencing","regr_avgx","regr_avgy","regr_count","regr_intercept","regr_r2","regr_slope","regr_sxx","regr_sxy","regr_syy","release","result","return","returns","revoke","right","rollback","rollup","row","row_number","rows","running","savepoint","scope","scroll","search","second","seek","select","sensitive","session_user","set","show","similar","sin","sinh","skip","smallint","some","specific","specifictype","sql","sqlexception","sqlstate","sqlwarning","sqrt","start","static","stddev_pop","stddev_samp","submultiset","subset","substring","substring_regex","succeeds","sum","symmetric","system","system_time","system_user","table","tablesample","tan","tanh","then","time","timestamp","timezone_hour","timezone_minute","to","trailing","translate","translate_regex","translation","treat","trigger","trim","trim_array","true","truncate","uescape","union","unique","unknown","unnest","update","upper","user","using","value","values","value_of","var_pop","var_samp","varbinary","varchar","varying","versioning","when","whenever","where","width_bucket","window","with","within","without","year","add","asc","collation","desc","final","first","last","view"].filter((e=>!a.includes(e))),i={ | |
| 4 | +match:r.concat(/\b/,r.either(...n),/\s*\(/),relevance:0,keywords:{built_in:n}} | |
| 5 | +;function o(e){ | |
| 6 | +return r.concat(/\b/,r.either(...e.map((e=>e.replace(/\s+/,"\\s+")))),/\b/)} | |
| 7 | +const c={scope:"keyword", | |
| 8 | +match:o(["create table","insert into","primary key","foreign key","not null","alter table","add constraint","grouping sets","on overflow","character set","respect nulls","ignore nulls","nulls first","nulls last","depth first","breadth first"]), | |
| 9 | +relevance:0};return{name:"SQL",case_insensitive:!0,illegal:/[{}]|<\//,keywords:{ | |
| 10 | +$pattern:/\b[\w\.]+/,keyword:((e,{exceptions:r,when:t}={})=>{const a=t | |
| 11 | +;return r=r||[],e.map((e=>e.match(/\|\d+$/)||r.includes(e)?e:a(e)?e+"|0":e)) | |
| 12 | +})(s,{when:e=>e.length<3}),literal:["true","false","unknown"], | |
| 13 | +type:["bigint","binary","blob","boolean","char","character","clob","date","dec","decfloat","decimal","float","int","integer","interval","nchar","nclob","national","numeric","real","row","smallint","time","timestamp","varchar","varying","varbinary"], | |
| 14 | +built_in:["current_catalog","current_date","current_default_transform_group","current_path","current_role","current_schema","current_transform_group_for_type","current_user","session_user","system_time","system_user","current_time","localtime","current_timestamp","localtimestamp"] | |
| 15 | +},contains:[{scope:"type", | |
| 16 | +match:o(["double precision","large object","with timezone","without timezone"]) | |
| 17 | +},c,i,{scope:"variable",match:/@[a-z0-9][a-z0-9_]*/},{scope:"string",variants:[{ | |
| 18 | +begin:/'/,end:/'/,contains:[{match:/''/}]}]},{begin:/"/,end:/"/,contains:[{ | |
| 19 | +match:/""/}]},e.C_NUMBER_MODE,e.C_BLOCK_COMMENT_MODE,t,{scope:"operator", | |
| 20 | +match:/[-+*/=%^~]|&&?|\|\|?|!=?|<(?:=>?|<|>)?|>[>=]?/,relevance:0}]}}})() | |
| 21 | +;export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/xml.js
... | ... | @@ -0,0 +1,249 @@ |
| 1 | +/*! `xml` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar = (function () { | |
| 3 | + 'use strict'; | |
| 4 | + | |
| 5 | + /* | |
| 6 | + Language: HTML, XML | |
| 7 | + Website: https://www.w3.org/XML/ | |
| 8 | + Category: common, web | |
| 9 | + Audit: 2020 | |
| 10 | + */ | |
| 11 | + | |
| 12 | + /** @type LanguageFn */ | |
| 13 | + function xml(hljs) { | |
| 14 | + const regex = hljs.regex; | |
| 15 | + // XML names can have the following additional letters: https://www.w3.org/TR/xml/#NT-NameChar | |
| 16 | + // OTHER_NAME_CHARS = /[:\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]/; | |
| 17 | + // Element names start with NAME_START_CHAR followed by optional other Unicode letters, ASCII digits, hyphens, underscores, and periods | |
| 18 | + // const TAG_NAME_RE = regex.concat(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/, regex.optional(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*:/), /[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*/);; | |
| 19 | + // const XML_IDENT_RE = /[A-Z_a-z:\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]+/; | |
| 20 | + // const TAG_NAME_RE = regex.concat(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD]/, regex.optional(/[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*:/), /[A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*/); | |
| 21 | + // however, to cater for performance and more Unicode support rely simply on the Unicode letter class | |
| 22 | + const TAG_NAME_RE = regex.concat(/[\p{L}_]/u, regex.optional(/[\p{L}0-9_.-]*:/u), /[\p{L}0-9_.-]*/u); | |
| 23 | + const XML_IDENT_RE = /[\p{L}0-9._:-]+/u; | |
| 24 | + const XML_ENTITIES = { | |
| 25 | + className: 'symbol', | |
| 26 | + begin: /&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/ | |
| 27 | + }; | |
| 28 | + const XML_META_KEYWORDS = { | |
| 29 | + begin: /\s/, | |
| 30 | + contains: [ | |
| 31 | + { | |
| 32 | + className: 'keyword', | |
| 33 | + begin: /#?[a-z_][a-z1-9_-]+/, | |
| 34 | + illegal: /\n/ | |
| 35 | + } | |
| 36 | + ] | |
| 37 | + }; | |
| 38 | + const XML_META_PAR_KEYWORDS = hljs.inherit(XML_META_KEYWORDS, { | |
| 39 | + begin: /\(/, | |
| 40 | + end: /\)/ | |
| 41 | + }); | |
| 42 | + const APOS_META_STRING_MODE = hljs.inherit(hljs.APOS_STRING_MODE, { className: 'string' }); | |
| 43 | + const QUOTE_META_STRING_MODE = hljs.inherit(hljs.QUOTE_STRING_MODE, { className: 'string' }); | |
| 44 | + const TAG_INTERNALS = { | |
| 45 | + endsWithParent: true, | |
| 46 | + illegal: /</, | |
| 47 | + relevance: 0, | |
| 48 | + contains: [ | |
| 49 | + { | |
| 50 | + className: 'attr', | |
| 51 | + begin: XML_IDENT_RE, | |
| 52 | + relevance: 0 | |
| 53 | + }, | |
| 54 | + { | |
| 55 | + begin: /=\s*/, | |
| 56 | + relevance: 0, | |
| 57 | + contains: [ | |
| 58 | + { | |
| 59 | + className: 'string', | |
| 60 | + endsParent: true, | |
| 61 | + variants: [ | |
| 62 | + { | |
| 63 | + begin: /"/, | |
| 64 | + end: /"/, | |
| 65 | + contains: [ XML_ENTITIES ] | |
| 66 | + }, | |
| 67 | + { | |
| 68 | + begin: /'/, | |
| 69 | + end: /'/, | |
| 70 | + contains: [ XML_ENTITIES ] | |
| 71 | + }, | |
| 72 | + { begin: /[^\s"'=<>`]+/ } | |
| 73 | + ] | |
| 74 | + } | |
| 75 | + ] | |
| 76 | + } | |
| 77 | + ] | |
| 78 | + }; | |
| 79 | + return { | |
| 80 | + name: 'HTML, XML', | |
| 81 | + aliases: [ | |
| 82 | + 'html', | |
| 83 | + 'xhtml', | |
| 84 | + 'rss', | |
| 85 | + 'atom', | |
| 86 | + 'xjb', | |
| 87 | + 'xsd', | |
| 88 | + 'xsl', | |
| 89 | + 'plist', | |
| 90 | + 'wsf', | |
| 91 | + 'svg' | |
| 92 | + ], | |
| 93 | + case_insensitive: true, | |
| 94 | + unicodeRegex: true, | |
| 95 | + contains: [ | |
| 96 | + { | |
| 97 | + className: 'meta', | |
| 98 | + begin: /<![a-z]/, | |
| 99 | + end: />/, | |
| 100 | + relevance: 10, | |
| 101 | + contains: [ | |
| 102 | + XML_META_KEYWORDS, | |
| 103 | + QUOTE_META_STRING_MODE, | |
| 104 | + APOS_META_STRING_MODE, | |
| 105 | + XML_META_PAR_KEYWORDS, | |
| 106 | + { | |
| 107 | + begin: /\[/, | |
| 108 | + end: /\]/, | |
| 109 | + contains: [ | |
| 110 | + { | |
| 111 | + className: 'meta', | |
| 112 | + begin: /<![a-z]/, | |
| 113 | + end: />/, | |
| 114 | + contains: [ | |
| 115 | + XML_META_KEYWORDS, | |
| 116 | + XML_META_PAR_KEYWORDS, | |
| 117 | + QUOTE_META_STRING_MODE, | |
| 118 | + APOS_META_STRING_MODE | |
| 119 | + ] | |
| 120 | + } | |
| 121 | + ] | |
| 122 | + } | |
| 123 | + ] | |
| 124 | + }, | |
| 125 | + hljs.COMMENT( | |
| 126 | + /<!--/, | |
| 127 | + /-->/, | |
| 128 | + { relevance: 10 } | |
| 129 | + ), | |
| 130 | + { | |
| 131 | + begin: /<!\[CDATA\[/, | |
| 132 | + end: /\]\]>/, | |
| 133 | + relevance: 10 | |
| 134 | + }, | |
| 135 | + XML_ENTITIES, | |
| 136 | + // xml processing instructions | |
| 137 | + { | |
| 138 | + className: 'meta', | |
| 139 | + end: /\?>/, | |
| 140 | + variants: [ | |
| 141 | + { | |
| 142 | + begin: /<\?xml/, | |
| 143 | + relevance: 10, | |
| 144 | + contains: [ | |
| 145 | + QUOTE_META_STRING_MODE | |
| 146 | + ] | |
| 147 | + }, | |
| 148 | + { | |
| 149 | + begin: /<\?[a-z][a-z0-9]+/, | |
| 150 | + } | |
| 151 | + ] | |
| 152 | + | |
| 153 | + }, | |
| 154 | + { | |
| 155 | + className: 'tag', | |
| 156 | + /* | |
| 157 | + The lookahead pattern (?=...) ensures that 'begin' only matches | |
| 158 | + '<style' as a single word, followed by a whitespace or an | |
| 159 | + ending bracket. | |
| 160 | + */ | |
| 161 | + begin: /<style(?=\s|>)/, | |
| 162 | + end: />/, | |
| 163 | + keywords: { name: 'style' }, | |
| 164 | + contains: [ TAG_INTERNALS ], | |
| 165 | + starts: { | |
| 166 | + end: /<\/style>/, | |
| 167 | + returnEnd: true, | |
| 168 | + subLanguage: [ | |
| 169 | + 'css', | |
| 170 | + 'xml' | |
| 171 | + ] | |
| 172 | + } | |
| 173 | + }, | |
| 174 | + { | |
| 175 | + className: 'tag', | |
| 176 | + // See the comment in the <style tag about the lookahead pattern | |
| 177 | + begin: /<script(?=\s|>)/, | |
| 178 | + end: />/, | |
| 179 | + keywords: { name: 'script' }, | |
| 180 | + contains: [ TAG_INTERNALS ], | |
| 181 | + starts: { | |
| 182 | + end: /<\/script>/, | |
| 183 | + returnEnd: true, | |
| 184 | + subLanguage: [ | |
| 185 | + 'javascript', | |
| 186 | + 'handlebars', | |
| 187 | + 'xml' | |
| 188 | + ] | |
| 189 | + } | |
| 190 | + }, | |
| 191 | + // we need this for now for jSX | |
| 192 | + { | |
| 193 | + className: 'tag', | |
| 194 | + begin: /<>|<\/>/ | |
| 195 | + }, | |
| 196 | + // open tag | |
| 197 | + { | |
| 198 | + className: 'tag', | |
| 199 | + begin: regex.concat( | |
| 200 | + /</, | |
| 201 | + regex.lookahead(regex.concat( | |
| 202 | + TAG_NAME_RE, | |
| 203 | + // <tag/> | |
| 204 | + // <tag> | |
| 205 | + // <tag ... | |
| 206 | + regex.either(/\/>/, />/, /\s/) | |
| 207 | + )) | |
| 208 | + ), | |
| 209 | + end: /\/?>/, | |
| 210 | + contains: [ | |
| 211 | + { | |
| 212 | + className: 'name', | |
| 213 | + begin: TAG_NAME_RE, | |
| 214 | + relevance: 0, | |
| 215 | + starts: TAG_INTERNALS | |
| 216 | + } | |
| 217 | + ] | |
| 218 | + }, | |
| 219 | + // close tag | |
| 220 | + { | |
| 221 | + className: 'tag', | |
| 222 | + begin: regex.concat( | |
| 223 | + /<\//, | |
| 224 | + regex.lookahead(regex.concat( | |
| 225 | + TAG_NAME_RE, />/ | |
| 226 | + )) | |
| 227 | + ), | |
| 228 | + contains: [ | |
| 229 | + { | |
| 230 | + className: 'name', | |
| 231 | + begin: TAG_NAME_RE, | |
| 232 | + relevance: 0 | |
| 233 | + }, | |
| 234 | + { | |
| 235 | + begin: />/, | |
| 236 | + relevance: 0, | |
| 237 | + endsParent: true | |
| 238 | + } | |
| 239 | + ] | |
| 240 | + } | |
| 241 | + ] | |
| 242 | + }; | |
| 243 | + } | |
| 244 | + | |
| 245 | + return xml; | |
| 246 | + | |
| 247 | +})(); | |
| 248 | +; | |
| 249 | +export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/languages/xml.min.js
... | ... | @@ -0,0 +1,29 @@ |
| 1 | +/*! `xml` grammar compiled for Highlight.js 11.11.1 */ | |
| 2 | +var hljsGrammar=(()=>{"use strict";return e=>{ | |
| 3 | +const a=e.regex,n=a.concat(/[\p{L}_]/u,a.optional(/[\p{L}0-9_.-]*:/u),/[\p{L}0-9_.-]*/u),s={ | |
| 4 | +className:"symbol",begin:/&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/},t={begin:/\s/, | |
| 5 | +contains:[{className:"keyword",begin:/#?[a-z_][a-z1-9_-]+/,illegal:/\n/}] | |
| 6 | +},i=e.inherit(t,{begin:/\(/,end:/\)/}),c=e.inherit(e.APOS_STRING_MODE,{ | |
| 7 | +className:"string"}),l=e.inherit(e.QUOTE_STRING_MODE,{className:"string"}),r={ | |
| 8 | +endsWithParent:!0,illegal:/</,relevance:0,contains:[{className:"attr", | |
| 9 | +begin:/[\p{L}0-9._:-]+/u,relevance:0},{begin:/=\s*/,relevance:0,contains:[{ | |
| 10 | +className:"string",endsParent:!0,variants:[{begin:/"/,end:/"/,contains:[s]},{ | |
| 11 | +begin:/'/,end:/'/,contains:[s]},{begin:/[^\s"'=<>`]+/}]}]}]};return{ | |
| 12 | +name:"HTML, XML", | |
| 13 | +aliases:["html","xhtml","rss","atom","xjb","xsd","xsl","plist","wsf","svg"], | |
| 14 | +case_insensitive:!0,unicodeRegex:!0,contains:[{className:"meta",begin:/<![a-z]/, | |
| 15 | +end:/>/,relevance:10,contains:[t,l,c,i,{begin:/\[/,end:/\]/,contains:[{ | |
| 16 | +className:"meta",begin:/<![a-z]/,end:/>/,contains:[t,i,l,c]}]}] | |
| 17 | +},e.COMMENT(/<!--/,/-->/,{relevance:10}),{begin:/<!\[CDATA\[/,end:/\]\]>/, | |
| 18 | +relevance:10},s,{className:"meta",end:/\?>/,variants:[{begin:/<\?xml/, | |
| 19 | +relevance:10,contains:[l]},{begin:/<\?[a-z][a-z0-9]+/}]},{className:"tag", | |
| 20 | +begin:/<style(?=\s|>)/,end:/>/,keywords:{name:"style"},contains:[r],starts:{ | |
| 21 | +end:/<\/style>/,returnEnd:!0,subLanguage:["css","xml"]}},{className:"tag", | |
| 22 | +begin:/<script(?=\s|>)/,end:/>/,keywords:{name:"script"},contains:[r],starts:{ | |
| 23 | +end:/<\/script>/,returnEnd:!0,subLanguage:["javascript","handlebars","xml"]}},{ | |
| 24 | +className:"tag",begin:/<>|<\/>/},{className:"tag", | |
| 25 | +begin:a.concat(/</,a.lookahead(a.concat(n,a.either(/\/>/,/>/,/\s/)))), | |
| 26 | +end:/\/?>/,contains:[{className:"name",begin:n,relevance:0,starts:r}]},{ | |
| 27 | +className:"tag",begin:a.concat(/<\//,a.lookahead(a.concat(n,/>/))),contains:[{ | |
| 28 | +className:"name",begin:n,relevance:0},{begin:/>/,relevance:0,endsParent:!0}]}]}} | |
| 29 | +})();export default hljsGrammar;(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/es/package.json
... | ... | @@ -0,0 +1,1 @@ |
| 1 | +{ "type": "module" }(No newline at end of file) |
+++ src/main/webapp/publish/js/highlight/highlight.js
| This file is too big to display. |
+++ src/main/webapp/publish/js/highlight/highlight.min.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/http.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/http.min.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/java.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/java.min.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/javascript.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/javascript.min.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/json.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/json.min.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/markdown.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/markdown.min.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/php.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/php.min.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/sql.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/sql.min.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/xml.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/languages/xml.min.js
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/package.json
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/styles/arta.css
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/styles/default.css
| This diff is skipped because there are too many other diffs. |
+++ src/main/webapp/publish/js/highlight/styles/default.min.css
| This diff is skipped because there are too many other diffs. |
Add a comment
Delete comment
Once you delete this comment, you won't be able to recover it. Are you sure you want to delete this comment?