2023-10-03 11:14:36 +08:00
|
|
|
/*
|
|
|
|
Language: XQuery
|
|
|
|
Author: Dirk Kirsten <dk@basex.org>
|
|
|
|
Contributor: Duncan Paterson
|
|
|
|
Description: Supports XQuery 3.1 including XQuery Update 3, so also XPath (as it is a superset)
|
|
|
|
Refactored to process xml constructor syntax and function-bodies. Added missing data-types, xpath operands, inbuilt functions, and query prologs
|
|
|
|
Website: https://www.w3.org/XML/Query/
|
|
|
|
Category: functional
|
|
|
|
Audit: 2020
|
|
|
|
*/
|
|
|
|
|
|
|
|
/** @type LanguageFn */
|
|
|
|
function xquery(_hljs) {
|
|
|
|
// see https://www.w3.org/TR/xquery/#id-terminal-delimitation
|
|
|
|
const KEYWORDS = [
|
|
|
|
"module",
|
|
|
|
"schema",
|
|
|
|
"namespace",
|
|
|
|
"boundary-space",
|
|
|
|
"preserve",
|
|
|
|
"no-preserve",
|
|
|
|
"strip",
|
|
|
|
"default",
|
|
|
|
"collation",
|
|
|
|
"base-uri",
|
|
|
|
"ordering",
|
|
|
|
"context",
|
|
|
|
"decimal-format",
|
|
|
|
"decimal-separator",
|
|
|
|
"copy-namespaces",
|
|
|
|
"empty-sequence",
|
|
|
|
"except",
|
|
|
|
"exponent-separator",
|
|
|
|
"external",
|
|
|
|
"grouping-separator",
|
|
|
|
"inherit",
|
|
|
|
"no-inherit",
|
|
|
|
"lax",
|
|
|
|
"minus-sign",
|
|
|
|
"per-mille",
|
|
|
|
"percent",
|
|
|
|
"schema-attribute",
|
|
|
|
"schema-element",
|
|
|
|
"strict",
|
|
|
|
"unordered",
|
|
|
|
"zero-digit",
|
|
|
|
"declare",
|
|
|
|
"import",
|
|
|
|
"option",
|
|
|
|
"function",
|
|
|
|
"validate",
|
|
|
|
"variable",
|
|
|
|
"for",
|
|
|
|
"at",
|
|
|
|
"in",
|
|
|
|
"let",
|
|
|
|
"where",
|
|
|
|
"order",
|
|
|
|
"group",
|
|
|
|
"by",
|
|
|
|
"return",
|
|
|
|
"if",
|
|
|
|
"then",
|
|
|
|
"else",
|
|
|
|
"tumbling",
|
|
|
|
"sliding",
|
|
|
|
"window",
|
|
|
|
"start",
|
|
|
|
"when",
|
|
|
|
"only",
|
|
|
|
"end",
|
|
|
|
"previous",
|
|
|
|
"next",
|
|
|
|
"stable",
|
|
|
|
"ascending",
|
|
|
|
"descending",
|
|
|
|
"allowing",
|
|
|
|
"empty",
|
|
|
|
"greatest",
|
|
|
|
"least",
|
|
|
|
"some",
|
|
|
|
"every",
|
|
|
|
"satisfies",
|
|
|
|
"switch",
|
|
|
|
"case",
|
|
|
|
"typeswitch",
|
|
|
|
"try",
|
|
|
|
"catch",
|
|
|
|
"and",
|
|
|
|
"or",
|
|
|
|
"to",
|
|
|
|
"union",
|
|
|
|
"intersect",
|
|
|
|
"instance",
|
|
|
|
"of",
|
|
|
|
"treat",
|
|
|
|
"as",
|
|
|
|
"castable",
|
|
|
|
"cast",
|
|
|
|
"map",
|
|
|
|
"array",
|
|
|
|
"delete",
|
|
|
|
"insert",
|
|
|
|
"into",
|
|
|
|
"replace",
|
|
|
|
"value",
|
|
|
|
"rename",
|
|
|
|
"copy",
|
|
|
|
"modify",
|
|
|
|
"update"
|
|
|
|
];
|
|
|
|
|
|
|
|
// Node Types (sorted by inheritance)
|
|
|
|
// atomic types (sorted by inheritance)
|
|
|
|
const TYPES = [
|
|
|
|
"item",
|
|
|
|
"document-node",
|
|
|
|
"node",
|
|
|
|
"attribute",
|
|
|
|
"document",
|
|
|
|
"element",
|
|
|
|
"comment",
|
|
|
|
"namespace",
|
|
|
|
"namespace-node",
|
|
|
|
"processing-instruction",
|
|
|
|
"text",
|
|
|
|
"construction",
|
|
|
|
"xs:anyAtomicType",
|
|
|
|
"xs:untypedAtomic",
|
|
|
|
"xs:duration",
|
|
|
|
"xs:time",
|
|
|
|
"xs:decimal",
|
|
|
|
"xs:float",
|
|
|
|
"xs:double",
|
|
|
|
"xs:gYearMonth",
|
|
|
|
"xs:gYear",
|
|
|
|
"xs:gMonthDay",
|
|
|
|
"xs:gMonth",
|
|
|
|
"xs:gDay",
|
|
|
|
"xs:boolean",
|
|
|
|
"xs:base64Binary",
|
|
|
|
"xs:hexBinary",
|
|
|
|
"xs:anyURI",
|
|
|
|
"xs:QName",
|
|
|
|
"xs:NOTATION",
|
|
|
|
"xs:dateTime",
|
|
|
|
"xs:dateTimeStamp",
|
|
|
|
"xs:date",
|
|
|
|
"xs:string",
|
|
|
|
"xs:normalizedString",
|
|
|
|
"xs:token",
|
|
|
|
"xs:language",
|
|
|
|
"xs:NMTOKEN",
|
|
|
|
"xs:Name",
|
|
|
|
"xs:NCName",
|
|
|
|
"xs:ID",
|
|
|
|
"xs:IDREF",
|
|
|
|
"xs:ENTITY",
|
|
|
|
"xs:integer",
|
|
|
|
"xs:nonPositiveInteger",
|
|
|
|
"xs:negativeInteger",
|
|
|
|
"xs:long",
|
|
|
|
"xs:int",
|
|
|
|
"xs:short",
|
|
|
|
"xs:byte",
|
|
|
|
"xs:nonNegativeInteger",
|
|
|
|
"xs:unisignedLong",
|
|
|
|
"xs:unsignedInt",
|
|
|
|
"xs:unsignedShort",
|
|
|
|
"xs:unsignedByte",
|
|
|
|
"xs:positiveInteger",
|
|
|
|
"xs:yearMonthDuration",
|
|
|
|
"xs:dayTimeDuration"
|
|
|
|
];
|
|
|
|
|
|
|
|
const LITERALS = [
|
|
|
|
"eq",
|
|
|
|
"ne",
|
|
|
|
"lt",
|
|
|
|
"le",
|
|
|
|
"gt",
|
|
|
|
"ge",
|
|
|
|
"is",
|
|
|
|
"self::",
|
|
|
|
"child::",
|
|
|
|
"descendant::",
|
|
|
|
"descendant-or-self::",
|
|
|
|
"attribute::",
|
|
|
|
"following::",
|
|
|
|
"following-sibling::",
|
|
|
|
"parent::",
|
|
|
|
"ancestor::",
|
|
|
|
"ancestor-or-self::",
|
|
|
|
"preceding::",
|
|
|
|
"preceding-sibling::",
|
|
|
|
"NaN"
|
|
|
|
];
|
|
|
|
|
|
|
|
// functions (TODO: find regex for op: without breaking build)
|
|
|
|
const BUILT_IN = {
|
|
|
|
className: 'built_in',
|
|
|
|
variants: [
|
|
|
|
{
|
|
|
|
begin: /\barray:/,
|
|
|
|
end: /(?:append|filter|flatten|fold-(?:left|right)|for-each(?:-pair)?|get|head|insert-before|join|put|remove|reverse|size|sort|subarray|tail)\b/
|
|
|
|
},
|
|
|
|
{
|
|
|
|
begin: /\bmap:/,
|
|
|
|
end: /(?:contains|entry|find|for-each|get|keys|merge|put|remove|size)\b/
|
|
|
|
},
|
|
|
|
{
|
|
|
|
begin: /\bmath:/,
|
|
|
|
end: /(?:a(?:cos|sin|tan[2]?)|cos|exp(?:10)?|log(?:10)?|pi|pow|sin|sqrt|tan)\b/
|
|
|
|
},
|
|
|
|
{
|
|
|
|
begin: /\bop:/,
|
|
|
|
end: /\(/,
|
|
|
|
excludeEnd: true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
begin: /\bfn:/,
|
|
|
|
end: /\(/,
|
|
|
|
excludeEnd: true
|
|
|
|
},
|
|
|
|
// do not highlight inbuilt strings as variable or xml element names
|
|
|
|
{ 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/ },
|
|
|
|
{
|
|
|
|
begin: /\blocal:/,
|
|
|
|
end: /\(/,
|
|
|
|
excludeEnd: true
|
|
|
|
},
|
|
|
|
{
|
|
|
|
begin: /\bzip:/,
|
|
|
|
end: /(?:zip-file|(?:xml|html|text|binary)-entry| (?:update-)?entries)\b/
|
|
|
|
},
|
|
|
|
{
|
|
|
|
begin: /\b(?:util|db|functx|app|xdmp|xmldb):/,
|
|
|
|
end: /\(/,
|
|
|
|
excludeEnd: true
|
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
|
|
|
|
const TITLE = {
|
|
|
|
className: 'title',
|
|
|
|
begin: /\bxquery version "[13]\.[01]"\s?(?:encoding ".+")?/,
|
|
|
|
end: /;/
|
|
|
|
};
|
|
|
|
|
|
|
|
const VAR = {
|
|
|
|
className: 'variable',
|
|
|
|
begin: /[$][\w\-:]+/
|
|
|
|
};
|
|
|
|
|
|
|
|
const NUMBER = {
|
|
|
|
className: 'number',
|
|
|
|
begin: /(\b0[0-7_]+)|(\b0x[0-9a-fA-F_]+)|(\b[1-9][0-9_]*(\.[0-9_]+)?)|[0_]\b/,
|
|
|
|
relevance: 0
|
|
|
|
};
|
|
|
|
|
|
|
|
const STRING = {
|
|
|
|
className: 'string',
|
|
|
|
variants: [
|
|
|
|
{
|
|
|
|
begin: /"/,
|
|
|
|
end: /"/,
|
|
|
|
contains: [
|
|
|
|
{
|
|
|
|
begin: /""/,
|
|
|
|
relevance: 0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
},
|
|
|
|
{
|
|
|
|
begin: /'/,
|
|
|
|
end: /'/,
|
|
|
|
contains: [
|
|
|
|
{
|
|
|
|
begin: /''/,
|
|
|
|
relevance: 0
|
|
|
|
}
|
|
|
|
]
|
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
|
|
|
|
const ANNOTATION = {
|
|
|
|
className: 'meta',
|
|
|
|
begin: /%[\w\-:]+/
|
|
|
|
};
|
|
|
|
|
|
|
|
const COMMENT = {
|
|
|
|
className: 'comment',
|
|
|
|
begin: /\(:/,
|
|
|
|
end: /:\)/,
|
|
|
|
relevance: 10,
|
|
|
|
contains: [
|
|
|
|
{
|
|
|
|
className: 'doctag',
|
|
|
|
begin: /@\w+/
|
|
|
|
}
|
|
|
|
]
|
|
|
|
};
|
|
|
|
|
|
|
|
// see https://www.w3.org/TR/xquery/#id-computedConstructors
|
|
|
|
// mocha: computed_inbuilt
|
|
|
|
// see https://www.regexpal.com/?fam=99749
|
|
|
|
const COMPUTED = {
|
|
|
|
beginKeywords: 'element attribute comment document processing-instruction',
|
|
|
|
end: /\{/,
|
|
|
|
excludeEnd: true
|
|
|
|
};
|
|
|
|
|
|
|
|
// mocha: direct_method
|
|
|
|
const DIRECT = {
|
|
|
|
begin: /<([\w._:-]+)(\s+\S*=('|").*('|"))?>/,
|
|
|
|
end: /(\/[\w._:-]+>)/,
|
|
|
|
subLanguage: 'xml',
|
|
|
|
contains: [
|
|
|
|
{
|
|
|
|
begin: /\{/,
|
|
|
|
end: /\}/,
|
|
|
|
subLanguage: 'xquery'
|
|
|
|
},
|
|
|
|
'self'
|
|
|
|
]
|
|
|
|
};
|
|
|
|
|
|
|
|
const CONTAINS = [
|
|
|
|
VAR,
|
|
|
|
BUILT_IN,
|
|
|
|
STRING,
|
|
|
|
NUMBER,
|
|
|
|
COMMENT,
|
|
|
|
ANNOTATION,
|
|
|
|
TITLE,
|
|
|
|
COMPUTED,
|
|
|
|
DIRECT
|
|
|
|
];
|
|
|
|
|
|
|
|
return {
|
|
|
|
name: 'XQuery',
|
|
|
|
aliases: [
|
|
|
|
'xpath',
|
|
|
|
'xq'
|
|
|
|
],
|
|
|
|
case_insensitive: false,
|
|
|
|
illegal: /(proc)|(abstract)|(extends)|(until)|(#)/,
|
|
|
|
keywords: {
|
|
|
|
$pattern: /[a-zA-Z$][a-zA-Z0-9_:-]*/,
|
|
|
|
keyword: KEYWORDS,
|
|
|
|
type: TYPES,
|
|
|
|
literal: LITERALS
|
|
|
|
},
|
|
|
|
contains: CONTAINS
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = xquery;
|