qml.js 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /**
  2. * @param {string} value
  3. * @returns {RegExp}
  4. * */
  5. /**
  6. * @param {RegExp | string } re
  7. * @returns {string}
  8. */
  9. function source(re) {
  10. if (!re) return null;
  11. if (typeof re === "string") return re;
  12. return re.source;
  13. }
  14. /**
  15. * @param {...(RegExp | string) } args
  16. * @returns {string}
  17. */
  18. function concat(...args) {
  19. const joined = args.map((x) => source(x)).join("");
  20. return joined;
  21. }
  22. /*
  23. Language: QML
  24. Requires: javascript.js, xml.js
  25. Author: John Foster <jfoster@esri.com>
  26. Description: Syntax highlighting for the Qt Quick QML scripting language, based mostly off
  27. the JavaScript parser.
  28. Website: https://doc.qt.io/qt-5/qmlapplications.html
  29. Category: scripting
  30. */
  31. function qml(hljs) {
  32. const KEYWORDS = {
  33. keyword:
  34. 'in of on if for while finally var new function do return void else break catch ' +
  35. 'instanceof with throw case default try this switch continue typeof delete ' +
  36. 'let yield const export super debugger as async await import',
  37. literal:
  38. 'true false null undefined NaN Infinity',
  39. built_in:
  40. 'eval isFinite isNaN parseFloat parseInt decodeURI decodeURIComponent ' +
  41. 'encodeURI encodeURIComponent escape unescape Object Function Boolean Error ' +
  42. 'EvalError InternalError RangeError ReferenceError StopIteration SyntaxError ' +
  43. 'TypeError URIError Number Math Date String RegExp Array Float32Array ' +
  44. 'Float64Array Int16Array Int32Array Int8Array Uint16Array Uint32Array ' +
  45. 'Uint8Array Uint8ClampedArray ArrayBuffer DataView JSON Intl arguments require ' +
  46. 'module console window document Symbol Set Map WeakSet WeakMap Proxy Reflect ' +
  47. 'Behavior bool color coordinate date double enumeration font geocircle georectangle ' +
  48. 'geoshape int list matrix4x4 parent point quaternion real rect ' +
  49. 'size string url variant vector2d vector3d vector4d ' +
  50. 'Promise'
  51. };
  52. const QML_IDENT_RE = '[a-zA-Z_][a-zA-Z0-9\\._]*';
  53. // Isolate property statements. Ends at a :, =, ;, ,, a comment or end of line.
  54. // Use property class.
  55. const PROPERTY = {
  56. className: 'keyword',
  57. begin: '\\bproperty\\b',
  58. starts: {
  59. className: 'string',
  60. end: '(:|=|;|,|//|/\\*|$)',
  61. returnEnd: true
  62. }
  63. };
  64. // Isolate signal statements. Ends at a ) a comment or end of line.
  65. // Use property class.
  66. const SIGNAL = {
  67. className: 'keyword',
  68. begin: '\\bsignal\\b',
  69. starts: {
  70. className: 'string',
  71. end: '(\\(|:|=|;|,|//|/\\*|$)',
  72. returnEnd: true
  73. }
  74. };
  75. // id: is special in QML. When we see id: we want to mark the id: as attribute and
  76. // emphasize the token following.
  77. const ID_ID = {
  78. className: 'attribute',
  79. begin: '\\bid\\s*:',
  80. starts: {
  81. className: 'string',
  82. end: QML_IDENT_RE,
  83. returnEnd: false
  84. }
  85. };
  86. // Find QML object attribute. An attribute is a QML identifier followed by :.
  87. // Unfortunately it's hard to know where it ends, as it may contain scalars,
  88. // objects, object definitions, or javascript. The true end is either when the parent
  89. // ends or the next attribute is detected.
  90. const QML_ATTRIBUTE = {
  91. begin: QML_IDENT_RE + '\\s*:',
  92. returnBegin: true,
  93. contains: [
  94. {
  95. className: 'attribute',
  96. begin: QML_IDENT_RE,
  97. end: '\\s*:',
  98. excludeEnd: true,
  99. relevance: 0
  100. }
  101. ],
  102. relevance: 0
  103. };
  104. // Find QML object. A QML object is a QML identifier followed by { and ends at the matching }.
  105. // All we really care about is finding IDENT followed by { and just mark up the IDENT and ignore the {.
  106. const QML_OBJECT = {
  107. begin: concat(QML_IDENT_RE, /\s*\{/),
  108. end: /\{/,
  109. returnBegin: true,
  110. relevance: 0,
  111. contains: [
  112. hljs.inherit(hljs.TITLE_MODE, {
  113. begin: QML_IDENT_RE
  114. })
  115. ]
  116. };
  117. return {
  118. name: 'QML',
  119. aliases: [ 'qt' ],
  120. case_insensitive: false,
  121. keywords: KEYWORDS,
  122. contains: [
  123. {
  124. className: 'meta',
  125. begin: /^\s*['"]use (strict|asm)['"]/
  126. },
  127. hljs.APOS_STRING_MODE,
  128. hljs.QUOTE_STRING_MODE,
  129. { // template string
  130. className: 'string',
  131. begin: '`',
  132. end: '`',
  133. contains: [
  134. hljs.BACKSLASH_ESCAPE,
  135. {
  136. className: 'subst',
  137. begin: '\\$\\{',
  138. end: '\\}'
  139. }
  140. ]
  141. },
  142. hljs.C_LINE_COMMENT_MODE,
  143. hljs.C_BLOCK_COMMENT_MODE,
  144. {
  145. className: 'number',
  146. variants: [
  147. {
  148. begin: '\\b(0[bB][01]+)'
  149. },
  150. {
  151. begin: '\\b(0[oO][0-7]+)'
  152. },
  153. {
  154. begin: hljs.C_NUMBER_RE
  155. }
  156. ],
  157. relevance: 0
  158. },
  159. { // "value" container
  160. begin: '(' + hljs.RE_STARTERS_RE + '|\\b(case|return|throw)\\b)\\s*',
  161. keywords: 'return throw case',
  162. contains: [
  163. hljs.C_LINE_COMMENT_MODE,
  164. hljs.C_BLOCK_COMMENT_MODE,
  165. hljs.REGEXP_MODE,
  166. { // E4X / JSX
  167. begin: /</,
  168. end: />\s*[);\]]/,
  169. relevance: 0,
  170. subLanguage: 'xml'
  171. }
  172. ],
  173. relevance: 0
  174. },
  175. SIGNAL,
  176. PROPERTY,
  177. {
  178. className: 'function',
  179. beginKeywords: 'function',
  180. end: /\{/,
  181. excludeEnd: true,
  182. contains: [
  183. hljs.inherit(hljs.TITLE_MODE, {
  184. begin: /[A-Za-z$_][0-9A-Za-z$_]*/
  185. }),
  186. {
  187. className: 'params',
  188. begin: /\(/,
  189. end: /\)/,
  190. excludeBegin: true,
  191. excludeEnd: true,
  192. contains: [
  193. hljs.C_LINE_COMMENT_MODE,
  194. hljs.C_BLOCK_COMMENT_MODE
  195. ]
  196. }
  197. ],
  198. illegal: /\[|%/
  199. },
  200. {
  201. // hack: prevents detection of keywords after dots
  202. begin: '\\.' + hljs.IDENT_RE,
  203. relevance: 0
  204. },
  205. ID_ID,
  206. QML_ATTRIBUTE,
  207. QML_OBJECT
  208. ],
  209. illegal: /#/
  210. };
  211. }
  212. module.exports = qml;