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.
287 lines
5.9 KiB
287 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;
|
|
|