diff options
Diffstat (limited to 'public/prism/prism-jsx.js')
| -rw-r--r-- | public/prism/prism-jsx.js | 185 |
1 files changed, 185 insertions, 0 deletions
diff --git a/public/prism/prism-jsx.js b/public/prism/prism-jsx.js new file mode 100644 index 0000000..7a0e922 --- /dev/null +++ b/public/prism/prism-jsx.js @@ -0,0 +1,185 @@ +(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); |
