xquery.js 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. /*
  2. Language: XQuery
  3. Author: Dirk Kirsten <dk@basex.org>
  4. Contributor: Duncan Paterson
  5. Description: Supports XQuery 3.1 including XQuery Update 3, so also XPath (as it is a superset)
  6. Refactored to process xml constructor syntax and function-bodies. Added missing data-types, xpath operands, inbuilt functions, and query prologs
  7. Website: https://www.w3.org/XML/Query/
  8. Category: functional
  9. Audit: 2020
  10. */
  11. /** @type LanguageFn */
  12. function xquery(_hljs) {
  13. // see https://www.w3.org/TR/xquery/#id-terminal-delimitation
  14. const KEYWORDS = [
  15. "module",
  16. "schema",
  17. "namespace",
  18. "boundary-space",
  19. "preserve",
  20. "no-preserve",
  21. "strip",
  22. "default",
  23. "collation",
  24. "base-uri",
  25. "ordering",
  26. "context",
  27. "decimal-format",
  28. "decimal-separator",
  29. "copy-namespaces",
  30. "empty-sequence",
  31. "except",
  32. "exponent-separator",
  33. "external",
  34. "grouping-separator",
  35. "inherit",
  36. "no-inherit",
  37. "lax",
  38. "minus-sign",
  39. "per-mille",
  40. "percent",
  41. "schema-attribute",
  42. "schema-element",
  43. "strict",
  44. "unordered",
  45. "zero-digit",
  46. "declare",
  47. "import",
  48. "option",
  49. "function",
  50. "validate",
  51. "variable",
  52. "for",
  53. "at",
  54. "in",
  55. "let",
  56. "where",
  57. "order",
  58. "group",
  59. "by",
  60. "return",
  61. "if",
  62. "then",
  63. "else",
  64. "tumbling",
  65. "sliding",
  66. "window",
  67. "start",
  68. "when",
  69. "only",
  70. "end",
  71. "previous",
  72. "next",
  73. "stable",
  74. "ascending",
  75. "descending",
  76. "allowing",
  77. "empty",
  78. "greatest",
  79. "least",
  80. "some",
  81. "every",
  82. "satisfies",
  83. "switch",
  84. "case",
  85. "typeswitch",
  86. "try",
  87. "catch",
  88. "and",
  89. "or",
  90. "to",
  91. "union",
  92. "intersect",
  93. "instance",
  94. "of",
  95. "treat",
  96. "as",
  97. "castable",
  98. "cast",
  99. "map",
  100. "array",
  101. "delete",
  102. "insert",
  103. "into",
  104. "replace",
  105. "value",
  106. "rename",
  107. "copy",
  108. "modify",
  109. "update"
  110. ];
  111. // Node Types (sorted by inheritance)
  112. // atomic types (sorted by inheritance)
  113. const TYPES = [
  114. "item",
  115. "document-node",
  116. "node",
  117. "attribute",
  118. "document",
  119. "element",
  120. "comment",
  121. "namespace",
  122. "namespace-node",
  123. "processing-instruction",
  124. "text",
  125. "construction",
  126. "xs:anyAtomicType",
  127. "xs:untypedAtomic",
  128. "xs:duration",
  129. "xs:time",
  130. "xs:decimal",
  131. "xs:float",
  132. "xs:double",
  133. "xs:gYearMonth",
  134. "xs:gYear",
  135. "xs:gMonthDay",
  136. "xs:gMonth",
  137. "xs:gDay",
  138. "xs:boolean",
  139. "xs:base64Binary",
  140. "xs:hexBinary",
  141. "xs:anyURI",
  142. "xs:QName",
  143. "xs:NOTATION",
  144. "xs:dateTime",
  145. "xs:dateTimeStamp",
  146. "xs:date",
  147. "xs:string",
  148. "xs:normalizedString",
  149. "xs:token",
  150. "xs:language",
  151. "xs:NMTOKEN",
  152. "xs:Name",
  153. "xs:NCName",
  154. "xs:ID",
  155. "xs:IDREF",
  156. "xs:ENTITY",
  157. "xs:integer",
  158. "xs:nonPositiveInteger",
  159. "xs:negativeInteger",
  160. "xs:long",
  161. "xs:int",
  162. "xs:short",
  163. "xs:byte",
  164. "xs:nonNegativeInteger",
  165. "xs:unisignedLong",
  166. "xs:unsignedInt",
  167. "xs:unsignedShort",
  168. "xs:unsignedByte",
  169. "xs:positiveInteger",
  170. "xs:yearMonthDuration",
  171. "xs:dayTimeDuration"
  172. ];
  173. const LITERALS = [
  174. "eq",
  175. "ne",
  176. "lt",
  177. "le",
  178. "gt",
  179. "ge",
  180. "is",
  181. "self::",
  182. "child::",
  183. "descendant::",
  184. "descendant-or-self::",
  185. "attribute::",
  186. "following::",
  187. "following-sibling::",
  188. "parent::",
  189. "ancestor::",
  190. "ancestor-or-self::",
  191. "preceding::",
  192. "preceding-sibling::",
  193. "NaN"
  194. ];
  195. // functions (TODO: find regex for op: without breaking build)
  196. const BUILT_IN = {
  197. className: 'built_in',
  198. variants: [
  199. {
  200. begin: /\barray:/,
  201. end: /(?:append|filter|flatten|fold-(?:left|right)|for-each(?:-pair)?|get|head|insert-before|join|put|remove|reverse|size|sort|subarray|tail)\b/
  202. },
  203. {
  204. begin: /\bmap:/,
  205. end: /(?:contains|entry|find|for-each|get|keys|merge|put|remove|size)\b/
  206. },
  207. {
  208. begin: /\bmath:/,
  209. end: /(?:a(?:cos|sin|tan[2]?)|cos|exp(?:10)?|log(?:10)?|pi|pow|sin|sqrt|tan)\b/
  210. },
  211. {
  212. begin: /\bop:/,
  213. end: /\(/,
  214. excludeEnd: true
  215. },
  216. {
  217. begin: /\bfn:/,
  218. end: /\(/,
  219. excludeEnd: true
  220. },
  221. // do not highlight inbuilt strings as variable or xml element names
  222. { begin: /[^</$:'"-]\b(?:abs|accumulator-(?:after|before)|adjust-(?:date(?:Time)?|time)-to-timezone|analyze-string|apply|available-(?:environment-variables|system-properties)|avg|base-uri|boolean|ceiling|codepoints?-(?:equal|to-string)|collation-key|collection|compare|concat|contains(?:-token)?|copy-of|count|current(?:-)?(?:date(?:Time)?|time|group(?:ing-key)?|output-uri|merge-(?:group|key))?data|dateTime|days?-from-(?:date(?:Time)?|duration)|deep-equal|default-(?:collation|language)|distinct-values|document(?:-uri)?|doc(?:-available)?|element-(?:available|with-id)|empty|encode-for-uri|ends-with|environment-variable|error|escape-html-uri|exactly-one|exists|false|filter|floor|fold-(?:left|right)|for-each(?:-pair)?|format-(?:date(?:Time)?|time|integer|number)|function-(?:arity|available|lookup|name)|generate-id|has-children|head|hours-from-(?:dateTime|duration|time)|id(?:ref)?|implicit-timezone|in-scope-prefixes|index-of|innermost|insert-before|iri-to-uri|json-(?:doc|to-xml)|key|lang|last|load-xquery-module|local-name(?:-from-QName)?|(?:lower|upper)-case|matches|max|minutes-from-(?:dateTime|duration|time)|min|months?-from-(?:date(?:Time)?|duration)|name(?:space-uri-?(?:for-prefix|from-QName)?)?|nilled|node-name|normalize-(?:space|unicode)|not|number|one-or-more|outermost|parse-(?:ietf-date|json)|path|position|(?:prefix-from-)?QName|random-number-generator|regex-group|remove|replace|resolve-(?:QName|uri)|reverse|root|round(?:-half-to-even)?|seconds-from-(?:dateTime|duration|time)|snapshot|sort|starts-with|static-base-uri|stream-available|string-?(?:join|length|to-codepoints)?|subsequence|substring-?(?:after|before)?|sum|system-property|tail|timezone-from-(?:date(?:Time)?|time)|tokenize|trace|trans(?:form|late)|true|type-available|unordered|unparsed-(?:entity|text)?-?(?:public-id|uri|available|lines)?|uri-collection|xml-to-json|years?-from-(?:date(?:Time)?|duration)|zero-or-one)\b/ },
  223. {
  224. begin: /\blocal:/,
  225. end: /\(/,
  226. excludeEnd: true
  227. },
  228. {
  229. begin: /\bzip:/,
  230. end: /(?:zip-file|(?:xml|html|text|binary)-entry| (?:update-)?entries)\b/
  231. },
  232. {
  233. begin: /\b(?:util|db|functx|app|xdmp|xmldb):/,
  234. end: /\(/,
  235. excludeEnd: true
  236. }
  237. ]
  238. };
  239. const TITLE = {
  240. className: 'title',
  241. begin: /\bxquery version "[13]\.[01]"\s?(?:encoding ".+")?/,
  242. end: /;/
  243. };
  244. const VAR = {
  245. className: 'variable',
  246. begin: /[$][\w\-:]+/
  247. };
  248. const NUMBER = {
  249. className: 'number',
  250. begin: /(\b0[0-7_]+)|(\b0x[0-9a-fA-F_]+)|(\b[1-9][0-9_]*(\.[0-9_]+)?)|[0_]\b/,
  251. relevance: 0
  252. };
  253. const STRING = {
  254. className: 'string',
  255. variants: [
  256. {
  257. begin: /"/,
  258. end: /"/,
  259. contains: [
  260. {
  261. begin: /""/,
  262. relevance: 0
  263. }
  264. ]
  265. },
  266. {
  267. begin: /'/,
  268. end: /'/,
  269. contains: [
  270. {
  271. begin: /''/,
  272. relevance: 0
  273. }
  274. ]
  275. }
  276. ]
  277. };
  278. const ANNOTATION = {
  279. className: 'meta',
  280. begin: /%[\w\-:]+/
  281. };
  282. const COMMENT = {
  283. className: 'comment',
  284. begin: /\(:/,
  285. end: /:\)/,
  286. relevance: 10,
  287. contains: [
  288. {
  289. className: 'doctag',
  290. begin: /@\w+/
  291. }
  292. ]
  293. };
  294. // see https://www.w3.org/TR/xquery/#id-computedConstructors
  295. // mocha: computed_inbuilt
  296. // see https://www.regexpal.com/?fam=99749
  297. const COMPUTED = {
  298. beginKeywords: 'element attribute comment document processing-instruction',
  299. end: /\{/,
  300. excludeEnd: true
  301. };
  302. // mocha: direct_method
  303. const DIRECT = {
  304. begin: /<([\w._:-]+)(\s+\S*=('|").*('|"))?>/,
  305. end: /(\/[\w._:-]+>)/,
  306. subLanguage: 'xml',
  307. contains: [
  308. {
  309. begin: /\{/,
  310. end: /\}/,
  311. subLanguage: 'xquery'
  312. },
  313. 'self'
  314. ]
  315. };
  316. const CONTAINS = [
  317. VAR,
  318. BUILT_IN,
  319. STRING,
  320. NUMBER,
  321. COMMENT,
  322. ANNOTATION,
  323. TITLE,
  324. COMPUTED,
  325. DIRECT
  326. ];
  327. return {
  328. name: 'XQuery',
  329. aliases: [
  330. 'xpath',
  331. 'xq',
  332. 'xqm'
  333. ],
  334. case_insensitive: false,
  335. illegal: /(proc)|(abstract)|(extends)|(until)|(#)/,
  336. keywords: {
  337. $pattern: /[a-zA-Z$][a-zA-Z0-9_:-]*/,
  338. keyword: KEYWORDS,
  339. type: TYPES,
  340. literal: LITERALS
  341. },
  342. contains: CONTAINS
  343. };
  344. }
  345. export { xquery as default };