123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145 |
- (function (Prism) {
- var javascript = Prism.util.clone(Prism.languages.javascript);
- var space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source;
- var braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source;
- var spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;
- /**
- * @param {string} source
- * @param {string} [flags]
- */
- function re(source, flags) {
- source = source
- .replace(/<S>/g, function () { return space; })
- .replace(/<BRACES>/g, function () { return braces; })
- .replace(/<SPREAD>/g, function () { return spread; });
- return RegExp(source, flags);
- }
- spread = re(spread).source;
- Prism.languages.jsx = Prism.languages.extend('markup', javascript);
- Prism.languages.jsx.tag.pattern = re(
- /<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/.source
- );
- Prism.languages.jsx.tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/;
- Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/;
- Prism.languages.jsx.tag.inside['tag'].inside['class-name'] = /^[A-Z]\w*(?:\.[A-Z]\w*)*$/;
- Prism.languages.jsx.tag.inside['comment'] = javascript['comment'];
- Prism.languages.insertBefore('inside', 'attr-name', {
- 'spread': {
- pattern: re(/<SPREAD>/.source),
- inside: Prism.languages.jsx
- }
- }, Prism.languages.jsx.tag);
- Prism.languages.insertBefore('inside', 'special-attr', {
- 'script': {
- // Allow for two levels of nesting
- pattern: re(/=<BRACES>/.source),
- alias: 'language-javascript',
- inside: {
- 'script-punctuation': {
- pattern: /^=(?=\{)/,
- alias: 'punctuation'
- },
- rest: Prism.languages.jsx
- },
- }
- }, Prism.languages.jsx.tag);
- // The following will handle plain text inside tags
- var stringifyToken = function (token) {
- if (!token) {
- return '';
- }
- if (typeof token === 'string') {
- return token;
- }
- if (typeof token.content === 'string') {
- return token.content;
- }
- return token.content.map(stringifyToken).join('');
- };
- var walkTokens = function (tokens) {
- var openedTags = [];
- for (var i = 0; i < tokens.length; i++) {
- var token = tokens[i];
- var notTagNorBrace = false;
- if (typeof token !== 'string') {
- if (token.type === 'tag' && token.content[0] && token.content[0].type === 'tag') {
- // We found a tag, now find its kind
- if (token.content[0].content[0].content === '</') {
- // Closing tag
- if (openedTags.length > 0 && openedTags[openedTags.length - 1].tagName === stringifyToken(token.content[0].content[1])) {
- // Pop matching opening tag
- openedTags.pop();
- }
- } else {
- if (token.content[token.content.length - 1].content === '/>') {
- // Autoclosed tag, ignore
- } else {
- // Opening tag
- openedTags.push({
- tagName: stringifyToken(token.content[0].content[1]),
- openedBraces: 0
- });
- }
- }
- } else if (openedTags.length > 0 && token.type === 'punctuation' && token.content === '{') {
- // Here we might have entered a JSX context inside a tag
- openedTags[openedTags.length - 1].openedBraces++;
- } else if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces > 0 && token.type === 'punctuation' && token.content === '}') {
- // Here we might have left a JSX context inside a tag
- openedTags[openedTags.length - 1].openedBraces--;
- } else {
- notTagNorBrace = true;
- }
- }
- if (notTagNorBrace || typeof token === 'string') {
- if (openedTags.length > 0 && openedTags[openedTags.length - 1].openedBraces === 0) {
- // Here we are inside a tag, and not inside a JSX context.
- // That's plain text: drop any tokens matched.
- var plainText = stringifyToken(token);
- // And merge text with adjacent text
- if (i < tokens.length - 1 && (typeof tokens[i + 1] === 'string' || tokens[i + 1].type === 'plain-text')) {
- plainText += stringifyToken(tokens[i + 1]);
- tokens.splice(i + 1, 1);
- }
- if (i > 0 && (typeof tokens[i - 1] === 'string' || tokens[i - 1].type === 'plain-text')) {
- plainText = stringifyToken(tokens[i - 1]) + plainText;
- tokens.splice(i - 1, 1);
- i--;
- }
- tokens[i] = new Prism.Token('plain-text', plainText, null, plainText);
- }
- }
- if (token.content && typeof token.content !== 'string') {
- walkTokens(token.content);
- }
- }
- };
- Prism.hooks.add('after-tokenize', function (env) {
- if (env.language !== 'jsx' && env.language !== 'tsx') {
- return;
- }
- walkTokens(env.tokens);
- });
- }(Prism));
|