UNPKG

reprism

Version:

Modular Syntax highlighting for the web

121 lines (108 loc) 4.56 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = { language: 'jsx', init: function init(Prism) { var javascript = Prism.util.clone(Prism.languages.javascript); Prism.languages.jsx = Prism.languages.extend('markup', javascript); Prism.languages.jsx.tag.pattern = /<\/?[\w.:-]+\s*(?:\s+(?:[\w.:-]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s{'">=]+|\{(?:\{[^}]*\}|[^{}])+\}))?|\{\.{3}[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\}))*\s*\/?>/i; Prism.languages.jsx.tag.inside['attr-value'].pattern = /=(?!\{)(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">]+)/i; Prism.languages.insertBefore('inside', 'attr-name', { spread: { pattern: /\{\.{3}[a-z_$][\w$]*(?:\.[a-z_$][\w$]*)*\}/, inside: { punctuation: /\.{3}|[{}.]/, 'attr-value': /\w+/ } } }, Prism.languages.jsx.tag); Prism.languages.insertBefore('inside', 'attr-value', { script: { // Allow for one level of nesting pattern: /=(\{(?:\{[^}]*\}|[^}])+\})/i, inside: { 'script-punctuation': { pattern: /^=(?={)/, alias: 'punctuation' }, rest: Prism.languages.jsx }, alias: 'language-javascript' } }, Prism.languages.jsx.tag); // The following will handle plain text inside tags var stringifyToken = function stringifyToken(token) { if (typeof token === 'string') { return token; } if (typeof token.content === 'string') { return token.content; } return token.content.map(stringifyToken).join(''); }; var walkTokens = function walkTokens(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); }); } };