You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
288 lines
5.9 KiB
288 lines
5.9 KiB
/**
|
|
* @param {string} value
|
|
* @returns {RegExp}
|
|
* */
|
|
|
|
/**
|
|
* @param {RegExp | string } re
|
|
* @returns {string}
|
|
*/
|
|
function source(re) {
|
|
if (!re) return null;
|
|
if (typeof re === "string") return re;
|
|
|
|
return re.source;
|
|
}
|
|
|
|
/**
|
|
* @param {RegExp | string } re
|
|
* @returns {string}
|
|
*/
|
|
function lookahead(re) {
|
|
return concat('(?=', re, ')');
|
|
}
|
|
|
|
/**
|
|
* @param {RegExp | string } re
|
|
* @returns {string}
|
|
*/
|
|
function optional(re) {
|
|
return concat('(', re, ')?');
|
|
}
|
|
|
|
/**
|
|
* @param {...(RegExp | string) } args
|
|
* @returns {string}
|
|
*/
|
|
function concat(...args) {
|
|
const joined = args.map((x) => source(x)).join("");
|
|
return joined;
|
|
}
|
|
|
|
/**
|
|
* Any of the passed expresssions may match
|
|
*
|
|
* Creates a huge this | this | that | that match
|
|
* @param {(RegExp | string)[] } args
|
|
* @returns {string}
|
|
*/
|
|
function either(...args) {
|
|
const joined = '(' + args.map((x) => source(x)).join("|") + ")";
|
|
return joined;
|
|
}
|
|
|
|
/*
|
|
Language: HTML, XML
|
|
Website: https://www.w3.org/XML/
|
|
Category: common
|
|
Audit: 2020
|
|
*/
|
|
|
|
/** @type LanguageFn */
|
|
function xml(hljs) {
|
|
// Element names can contain letters, digits, hyphens, underscores, and periods
|
|
const TAG_NAME_RE = concat(/[A-Z_]/, optional(/[A-Z0-9_.-]*:/), /[A-Z0-9_.-]*/);
|
|
const XML_IDENT_RE = /[A-Za-z0-9._:-]+/;
|
|
const XML_ENTITIES = {
|
|
className: 'symbol',
|
|
begin: /&[a-z]+;|&#[0-9]+;|&#x[a-f0-9]+;/
|
|
};
|
|
const XML_META_KEYWORDS = {
|
|
begin: /\s/,
|
|
contains: [
|
|
{
|
|
className: 'meta-keyword',
|
|
begin: /#?[a-z_][a-z1-9_-]+/,
|
|
illegal: /\n/
|
|
}
|
|
]
|
|
};
|
|
const XML_META_PAR_KEYWORDS = hljs.inherit(XML_META_KEYWORDS, {
|
|
begin: /\(/,
|
|
end: /\)/
|
|
});
|
|
const APOS_META_STRING_MODE = hljs.inherit(hljs.APOS_STRING_MODE, {
|
|
className: 'meta-string'
|
|
});
|
|
const QUOTE_META_STRING_MODE = hljs.inherit(hljs.QUOTE_STRING_MODE, {
|
|
className: 'meta-string'
|
|
});
|
|
const TAG_INTERNALS = {
|
|
endsWithParent: true,
|
|
illegal: /</,
|
|
relevance: 0,
|
|
contains: [
|
|
{
|
|
className: 'attr',
|
|
begin: XML_IDENT_RE,
|
|
relevance: 0
|
|
},
|
|
{
|
|
begin: /=\s*/,
|
|
relevance: 0,
|
|
contains: [
|
|
{
|
|
className: 'string',
|
|
endsParent: true,
|
|
variants: [
|
|
{
|
|
begin: /"/,
|
|
end: /"/,
|
|
contains: [ XML_ENTITIES ]
|
|
},
|
|
{
|
|
begin: /'/,
|
|
end: /'/,
|
|
contains: [ XML_ENTITIES ]
|
|
},
|
|
{
|
|
begin: /[^\s"'=<>`]+/
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
};
|
|
return {
|
|
name: 'HTML, XML',
|
|
aliases: [
|
|
'html',
|
|
'xhtml',
|
|
'rss',
|
|
'atom',
|
|
'xjb',
|
|
'xsd',
|
|
'xsl',
|
|
'plist',
|
|
'wsf',
|
|
'svg'
|
|
],
|
|
case_insensitive: true,
|
|
contains: [
|
|
{
|
|
className: 'meta',
|
|
begin: /<![a-z]/,
|
|
end: />/,
|
|
relevance: 10,
|
|
contains: [
|
|
XML_META_KEYWORDS,
|
|
QUOTE_META_STRING_MODE,
|
|
APOS_META_STRING_MODE,
|
|
XML_META_PAR_KEYWORDS,
|
|
{
|
|
begin: /\[/,
|
|
end: /\]/,
|
|
contains: [
|
|
{
|
|
className: 'meta',
|
|
begin: /<![a-z]/,
|
|
end: />/,
|
|
contains: [
|
|
XML_META_KEYWORDS,
|
|
XML_META_PAR_KEYWORDS,
|
|
QUOTE_META_STRING_MODE,
|
|
APOS_META_STRING_MODE
|
|
]
|
|
}
|
|
]
|
|
}
|
|
]
|
|
},
|
|
hljs.COMMENT(
|
|
/<!--/,
|
|
/-->/,
|
|
{
|
|
relevance: 10
|
|
}
|
|
),
|
|
{
|
|
begin: /<!\[CDATA\[/,
|
|
end: /\]\]>/,
|
|
relevance: 10
|
|
},
|
|
XML_ENTITIES,
|
|
{
|
|
className: 'meta',
|
|
begin: /<\?xml/,
|
|
end: /\?>/,
|
|
relevance: 10
|
|
},
|
|
{
|
|
className: 'tag',
|
|
/*
|
|
The lookahead pattern (?=...) ensures that 'begin' only matches
|
|
'<style' as a single word, followed by a whitespace or an
|
|
ending braket. The '$' is needed for the lexeme to be recognized
|
|
by hljs.subMode() that tests lexemes outside the stream.
|
|
*/
|
|
begin: /<style(?=\s|>)/,
|
|
end: />/,
|
|
keywords: {
|
|
name: 'style'
|
|
},
|
|
contains: [ TAG_INTERNALS ],
|
|
starts: {
|
|
end: /<\/style>/,
|
|
returnEnd: true,
|
|
subLanguage: [
|
|
'css',
|
|
'xml'
|
|
]
|
|
}
|
|
},
|
|
{
|
|
className: 'tag',
|
|
// See the comment in the <style tag about the lookahead pattern
|
|
begin: /<script(?=\s|>)/,
|
|
end: />/,
|
|
keywords: {
|
|
name: 'script'
|
|
},
|
|
contains: [ TAG_INTERNALS ],
|
|
starts: {
|
|
end: /<\/script>/,
|
|
returnEnd: true,
|
|
subLanguage: [
|
|
'javascript',
|
|
'handlebars',
|
|
'xml'
|
|
]
|
|
}
|
|
},
|
|
// we need this for now for jSX
|
|
{
|
|
className: 'tag',
|
|
begin: /<>|<\/>/
|
|
},
|
|
// open tag
|
|
{
|
|
className: 'tag',
|
|
begin: concat(
|
|
/</,
|
|
lookahead(concat(
|
|
TAG_NAME_RE,
|
|
// <tag/>
|
|
// <tag>
|
|
// <tag ...
|
|
either(/\/>/, />/, /\s/)
|
|
))
|
|
),
|
|
end: /\/?>/,
|
|
contains: [
|
|
{
|
|
className: 'name',
|
|
begin: TAG_NAME_RE,
|
|
relevance: 0,
|
|
starts: TAG_INTERNALS
|
|
}
|
|
]
|
|
},
|
|
// close tag
|
|
{
|
|
className: 'tag',
|
|
begin: concat(
|
|
/<\//,
|
|
lookahead(concat(
|
|
TAG_NAME_RE, />/
|
|
))
|
|
),
|
|
contains: [
|
|
{
|
|
className: 'name',
|
|
begin: TAG_NAME_RE,
|
|
relevance: 0
|
|
},
|
|
{
|
|
begin: />/,
|
|
relevance: 0,
|
|
endsParent: true
|
|
}
|
|
]
|
|
}
|
|
]
|
|
};
|
|
}
|
|
|
|
module.exports = xml;
|