'use strict' module.exports = textile textile.displayName = 'textile' textile.aliases = [] function textile(Prism) { ;(function (Prism) { // We don't allow for pipes inside parentheses // to not break table pattern |(. foo |). bar | var modifierRegex = /\([^|()\n]+\)|\[[^\]\n]+\]|\{[^}\n]+\}/.source // Opening and closing parentheses which are not a modifier // This pattern is necessary to prevent exponential backtracking var parenthesesRegex = /\)|\((?![^|()\n]+\))/.source /** * @param {string} source * @param {string} [flags] */ function withModifier(source, flags) { return RegExp( source .replace(//g, function () { return '(?:' + modifierRegex + ')' }) .replace(//g, function () { return '(?:' + parenthesesRegex + ')' }), flags || '' ) } var modifierTokens = { css: { pattern: /\{[^{}]+\}/, inside: { rest: Prism.languages.css } }, 'class-id': { pattern: /(\()[^()]+(?=\))/, lookbehind: true, alias: 'attr-value' }, lang: { pattern: /(\[)[^\[\]]+(?=\])/, lookbehind: true, alias: 'attr-value' }, // Anything else is punctuation (the first pattern is for row/col spans inside tables) punctuation: /[\\\/]\d+|\S/ } var textile = (Prism.languages.textile = Prism.languages.extend('markup', { phrase: { pattern: /(^|\r|\n)\S[\s\S]*?(?=$|\r?\n\r?\n|\r\r)/, lookbehind: true, inside: { // h1. Header 1 'block-tag': { pattern: withModifier(/^[a-z]\w*(?:||[<>=])*\./.source), inside: { modifier: { pattern: withModifier( /(^[a-z]\w*)(?:||[<>=])+(?=\.)/.source ), lookbehind: true, inside: modifierTokens }, tag: /^[a-z]\w*/, punctuation: /\.$/ } }, // # List item // * List item list: { pattern: withModifier(/^[*#]+*\s+\S.*/.source, 'm'), inside: { modifier: { pattern: withModifier(/(^[*#]+)+/.source), lookbehind: true, inside: modifierTokens }, punctuation: /^[*#]+/ } }, // | cell | cell | cell | table: { // Modifiers can be applied to the row: {color:red}.|1|2|3| // or the cell: |{color:red}.1|2|3| pattern: withModifier( /^(?:(?:||[<>=^~])+\.\s*)?(?:\|(?:(?:||[<>=^~_]|[\\/]\d+)+\.|(?!(?:||[<>=^~_]|[\\/]\d+)+\.))[^|]*)+\|/ .source, 'm' ), inside: { modifier: { // Modifiers for rows after the first one are // preceded by a pipe and a line feed pattern: withModifier( /(^|\|(?:\r?\n|\r)?)(?:||[<>=^~_]|[\\/]\d+)+(?=\.)/ .source ), lookbehind: true, inside: modifierTokens }, punctuation: /\||^\./ } }, inline: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier( /(^|[^a-zA-Z\d])(\*\*|__|\?\?|[*_%@+\-^~])*.+?\2(?![a-zA-Z\d])/ .source ), lookbehind: true, inside: { // Note: superscripts and subscripts are not handled specifically // *bold*, **bold** bold: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^(\*\*?)*).+?(?=\2)/.source), lookbehind: true }, // _italic_, __italic__ italic: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^(__?)*).+?(?=\2)/.source), lookbehind: true }, // ??cite?? cite: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^\?\?*).+?(?=\?\?)/.source), lookbehind: true, alias: 'string' }, // @code@ code: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^@*).+?(?=@)/.source), lookbehind: true, alias: 'keyword' }, // +inserted+ inserted: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^\+*).+?(?=\+)/.source), lookbehind: true }, // -deleted- deleted: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^-*).+?(?=-)/.source), lookbehind: true }, // %span% span: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^%*).+?(?=%)/.source), lookbehind: true }, modifier: { pattern: withModifier( /(^\*\*|__|\?\?|[*_%@+\-^~])+/.source ), lookbehind: true, inside: modifierTokens }, punctuation: /[*_%?@+\-^~]+/ } }, // [alias]http://example.com 'link-ref': { pattern: /^\[[^\]]+\]\S+$/m, inside: { string: { pattern: /(^\[)[^\]]+(?=\])/, lookbehind: true }, url: { pattern: /(^\])\S+$/, lookbehind: true }, punctuation: /[\[\]]/ } }, // "text":http://example.com // "text":link-ref link: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier( /"*[^"]+":.+?(?=[^\w/]?(?:\s|$))/.source ), inside: { text: { // eslint-disable-next-line regexp/no-super-linear-backtracking pattern: withModifier(/(^"*)[^"]+(?=")/.source), lookbehind: true }, modifier: { pattern: withModifier(/(^")+/.source), lookbehind: true, inside: modifierTokens }, url: { pattern: /(:).+/, lookbehind: true }, punctuation: /[":]/ } }, // !image.jpg! // !image.jpg(Title)!:http://example.com image: { pattern: withModifier( /!(?:||[<>=])*(?![<>=])[^!\s()]+(?:\([^)]+\))?!(?::.+?(?=[^\w/]?(?:\s|$)))?/ .source ), inside: { source: { pattern: withModifier( /(^!(?:||[<>=])*)(?![<>=])[^!\s()]+(?:\([^)]+\))?(?=!)/ .source ), lookbehind: true, alias: 'url' }, modifier: { pattern: withModifier(/(^!)(?:||[<>=])+/.source), lookbehind: true, inside: modifierTokens }, url: { pattern: /(:).+/, lookbehind: true }, punctuation: /[!:]/ } }, // Footnote[1] footnote: { pattern: /\b\[\d+\]/, alias: 'comment', inside: { punctuation: /\[|\]/ } }, // CSS(Cascading Style Sheet) acronym: { pattern: /\b[A-Z\d]+\([^)]+\)/, inside: { comment: { pattern: /(\()[^()]+(?=\))/, lookbehind: true }, punctuation: /[()]/ } }, // Prism(C) mark: { pattern: /\b\((?:C|R|TM)\)/, alias: 'comment', inside: { punctuation: /[()]/ } } } } })) var phraseInside = textile['phrase'].inside var nestedPatterns = { inline: phraseInside['inline'], link: phraseInside['link'], image: phraseInside['image'], footnote: phraseInside['footnote'], acronym: phraseInside['acronym'], mark: phraseInside['mark'] } // Only allow alpha-numeric HTML tags, not XML tags textile.tag.pattern = /<\/?(?!\d)[a-z0-9]+(?:\s+[^\s>\/=]+(?:=(?:("|')(?:\\[\s\S]|(?!\1)[^\\])*\1|[^\s'">=]+))?)*\s*\/?>/i // Allow some nesting var phraseInlineInside = phraseInside['inline'].inside phraseInlineInside['bold'].inside = nestedPatterns phraseInlineInside['italic'].inside = nestedPatterns phraseInlineInside['inserted'].inside = nestedPatterns phraseInlineInside['deleted'].inside = nestedPatterns phraseInlineInside['span'].inside = nestedPatterns // Allow some styles inside table cells var phraseTableInside = phraseInside['table'].inside phraseTableInside['inline'] = nestedPatterns['inline'] phraseTableInside['link'] = nestedPatterns['link'] phraseTableInside['image'] = nestedPatterns['image'] phraseTableInside['footnote'] = nestedPatterns['footnote'] phraseTableInside['acronym'] = nestedPatterns['acronym'] phraseTableInside['mark'] = nestedPatterns['mark'] })(Prism) }