diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 0000000..b66c2f0 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,136 @@ +{ + "parserOptions": { + "ecmaVersion": 6, + "sourceType": "module" + }, + + "env": { + "es6": true, + "node": true + }, + + "globals": { + "document": false, + "navigator": false, + "window": false + }, + + "rules": { + "accessor-pairs": 2, + "arrow-spacing": [2, { "before": true, "after": true }], + "block-spacing": [2, "always"], + "brace-style": [2, "stroustrup", { "allowSingleLine": true }], + "camelcase": [2, { "properties": "never" }], + "comma-dangle": [2, "never"], + "comma-spacing": [2, { "before": false, "after": true }], + "comma-style": [2, "last"], + "constructor-super": 2, + "curly": [2, "multi-line"], + "dot-location": [2, "property"], + "eol-last": 2, + "eqeqeq": [2, "allow-null"], + "generator-star-spacing": [2, { "before": true, "after": true }], + "handle-callback-err": [2, "^(err|error)$" ], + "indent": [2, 2, { "SwitchCase": 1 }], + "jsx-quotes": [2, "prefer-single"], + "key-spacing": [2, { "beforeColon": false, "afterColon": true }], + "keyword-spacing": [2, { "before": true, "after": true }], + "new-cap": [2, { "newIsCap": true, "capIsNew": false }], + "new-parens": 2, + "no-array-constructor": 2, + "no-caller": 2, + "no-class-assign": 2, + "no-cond-assign": 2, + "no-const-assign": 2, + "no-control-regex": 2, + "no-debugger": 2, + "no-delete-var": 2, + "no-dupe-args": 2, + "no-dupe-class-members": 2, + "no-dupe-keys": 2, + "no-duplicate-case": 2, + "no-duplicate-imports": 2, + "no-empty-character-class": 2, + "no-empty-pattern": 2, + "no-eval": 2, + "no-ex-assign": 2, + "no-extend-native": 2, + "no-extra-bind": 2, + "no-extra-boolean-cast": 2, + "no-extra-parens": [2, "functions"], + "no-fallthrough": 2, + "no-floating-decimal": 2, + "no-func-assign": 2, + "no-implied-eval": 2, + "no-inner-declarations": [2, "functions"], + "no-invalid-regexp": 2, + "no-irregular-whitespace": 2, + "no-iterator": 2, + "no-label-var": 2, + "no-labels": [2, { "allowLoop": false, "allowSwitch": false }], + "no-lone-blocks": 2, + "no-mixed-spaces-and-tabs": 2, + "no-multi-spaces": 2, + "no-multi-str": 2, + "no-multiple-empty-lines": [2, { "max": 1 }], + "no-native-reassign": 2, + "no-negated-in-lhs": 2, + "no-new": 2, + "no-new-func": 2, + "no-new-object": 2, + "no-new-require": 2, + "no-new-symbol": 2, + "no-new-wrappers": 2, + "no-obj-calls": 2, + "no-octal": 2, + "no-octal-escape": 2, + "no-path-concat": 2, + "no-proto": 2, + "no-redeclare": 2, + "no-regex-spaces": 2, + "no-return-assign": [2, "except-parens"], + "no-self-assign": 2, + "no-self-compare": 2, + "no-sequences": 2, + "no-shadow-restricted-names": 2, + "no-spaced-func": 2, + "no-sparse-arrays": 2, + "no-this-before-super": 2, + "no-throw-literal": 2, + "no-trailing-spaces": 2, + "no-undef": 2, + "no-undef-init": 2, + "no-unexpected-multiline": 2, + "no-unmodified-loop-condition": 2, + "no-unneeded-ternary": [2, { "defaultAssignment": false }], + "no-unreachable": 2, + "no-unsafe-finally": 2, + "no-unused-vars": [2, { "vars": "all", "args": "none" }], + "no-useless-call": 2, + "no-useless-computed-key": 2, + "no-useless-constructor": 2, + "no-useless-escape": 2, + "no-var": 1, + "no-whitespace-before-property": 2, + "no-with": 2, + "one-var": [2, { "initialized": "never" }], + "operator-linebreak": [2, "after", { "overrides": { "?": "before", ":": "before" } }], + "padded-blocks": [2, "never"], + "prefer-const": 1, + "quotes": [2, "single", "avoid-escape"], + "semi": [2, "always"], + "semi-spacing": [2, { "before": false, "after": true }], + "space-before-blocks": [2, "always"], + "space-before-function-paren": [2, "always"], + "space-in-parens": ["error", "always", { "exceptions": ["{}", "empty"] }], + "space-infix-ops": 2, + "space-unary-ops": [2, { "words": true, "nonwords": false }], + "spaced-comment": [2, "always", { "markers": ["global", "globals", "eslint", "eslint-disable", "*package", "!", ","] }], + "template-curly-spacing": [2, "always"], + "use-isnan": 2, + "valid-typeof": 2, + "wrap-iife": [2, "any"], + "yield-star-spacing": [2, "both"], + "yoda": [2, "never"], + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0fd0949 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +_* +node_modules +logs +*.log +npm-debug.log* +.npm +*.sh diff --git a/Makefile b/Makefile deleted file mode 100644 index 36f2248..0000000 --- a/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -all: - @cp lib/textile.js textile.js - @uglifyjs -o textile.min.js textile.js - -clean: - @rm textile.js - @rm textile.min.js - -test: - @node test/index.js - -.PHONY: clean all test diff --git a/bin/textile b/bin/textile index 5136a94..eccd0e3 100755 --- a/bin/textile +++ b/bin/textile @@ -1,20 +1,29 @@ #!/usr/bin/env node -var fs = require('fs') - , util = require('util') - , textile = require('../') - ; +var fs = require( 'fs' ); + +var textile; +var nodeVersion = process && process.versions && process.versions.node; +// is this node version mostly ES6 complete +if ( parseInt( nodeVersion || 0, 10 ) > 5 ) { + // serve code from src dir + textile = require( '../src' ); +} +else { + // serve transpiled code + textile = require( '../dist/textile' ); +} // clean arguments var args = []; -process.argv.slice(2).forEach(function ( m, i, s ) { - if ( s = /^([^=]+)=(.*)$/.exec( m ) ) { +process.argv.slice( 2 ).forEach( function ( m, i, s ) { + if ( ( s = /^([^=]+)=(.*)$/.exec( m ) ) ) { args.push( s[1], s[2] ); } else { args.push( m ); } -}) +}); // parse arguments var options = {}; @@ -41,12 +50,10 @@ if ( options.input ) { } // writer -var data = ""; -function write_data () { - data = options.tokens - ? JSON.stringify( textile.jsonml( data ), null, 2 ) - : textile( data ) - ; +var data = ''; +function writeData () { + data = options.tokens ? JSON.stringify( textile.jsonml( data ), null, 2 ) + : textile( data ); if ( options.output ) { fs.writeFileSync( options.output, data ); } @@ -58,14 +65,14 @@ function write_data () { // file or stdin? if ( options.files ) { data = fs.readFileSync( options.files[0], 'utf8' ); - write_data(); + writeData(); } else { - var stdin = process.stdin; + const stdin = process.stdin; stdin.setEncoding( 'utf8' ); stdin.on( 'data', function ( text ) { data += text; }); - stdin.on( 'end', write_data ); + stdin.on( 'end', writeData ); stdin.resume(); } diff --git a/dist/textile.js b/dist/textile.js new file mode 100644 index 0000000..98b2571 --- /dev/null +++ b/dist/textile.js @@ -0,0 +1,1836 @@ +(function webpackUniversalModuleDefinition(root, factory) { + if(typeof exports === 'object' && typeof module === 'object') + module.exports = factory(); + else if(typeof define === 'function' && define.amd) + define("textile", [], factory); + else if(typeof exports === 'object') + exports["textile"] = factory(); + else + root["textile"] = factory(); +})(this, function() { +return /******/ (function(modules) { // webpackBootstrap +/******/ // The module cache +/******/ var installedModules = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; +/******/ +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false +/******/ }; +/******/ +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); +/******/ +/******/ // Flag the module as loaded +/******/ module.loaded = true; +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/******/ +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; +/******/ +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; +/******/ +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; +/******/ +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + /* + ** Textile parser for JavaScript + ** + ** Copyright (c) 2012 Borgar Þorsteinsson (MIT License). + ** + */ + + var merge = __webpack_require__(1); + + var _require = __webpack_require__(2); + + var toHTML = _require.toHTML; + + var _require2 = __webpack_require__(6); + + var parseFlow = _require2.parseFlow; + + var _require3 = __webpack_require__(3); + + var parseHtml = _require3.parseHtml; + + + function textile(txt, opt) { + // get a throw-away copy of options + opt = merge(merge({}, textile.defaults), opt || {}); + // run the converter + return parseFlow(txt, opt).map(toHTML).join(''); + }; + module.exports = textile; + + // options + textile.defaults = { + // single-line linebreaks are converted to
by default + 'breaks': true + }; + textile.setOptions = textile.setoptions = function (opt) { + merge(textile.defaults, opt); + return this; + }; + + textile.parse = textile.convert = textile; + textile.html_parser = parseHtml; + + textile.jsonml = function (txt, opt) { + // get a throw-away copy of options + opt = merge(merge({}, textile.defaults), opt || {}); + // parse and return tree + return ['html'].concat(parseFlow(txt, opt)); + }; + textile.serialize = toHTML; + +/***/ }, +/* 1 */ +/***/ function(module, exports) { + + "use strict"; + + // merge object b properties into object a + module.exports = function merge(a, b) { + if (b) { + for (var k in b) { + a[k] = b[k]; + } + } + return a; + }; + +/***/ }, +/* 2 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; + + /* + ** JSONML helper methods - http://www.jsonml.org/ + ** + ** This provides the `JSONML` object, which contains helper + ** methods for rendering JSONML to HTML. + ** + ** Note that the tag ! is taken to mean comment, this is however + ** not specified in the JSONML spec. + */ + + var singletons = __webpack_require__(3).singletons; + + // drop or add tab levels to JsonML tree + function reIndent(ml, shiftBy) { + // a bit obsessive, but there we are... + if (!shiftBy) { + return ml; + } + return ml.map(function (s) { + if (/^\n\t+/.test(s)) { + if (shiftBy < 0) { + s = s.slice(0, shiftBy); + } else { + for (var i = 0; i < shiftBy; i++) { + s += '\t'; + } + } + } else if (Array.isArray(s)) { + return reIndent(s, shiftBy); + } + return s; + }); + } + + function escape(text, escapeQuotes) { + return text.replace(/&(?!(#\d{2,}|#x[\da-fA-F]{2,}|[a-zA-Z][a-zA-Z1-4]{1,6});)/g, '&').replace(//g, '>').replace(/"/g, escapeQuotes ? '"' : '"').replace(/'/g, escapeQuotes ? ''' : "'"); + } + + function toHTML(jsonml) { + jsonml = jsonml.concat(); + + // basic case + if (typeof jsonml === 'string') { + return escape(jsonml); + } + + var tag = jsonml.shift(); + var attributes = {}; + var tagAttrs = ''; + var content = []; + + if (jsonml.length && _typeof(jsonml[0]) === 'object' && !Array.isArray(jsonml[0])) { + attributes = jsonml.shift(); + } + + while (jsonml.length) { + content.push(toHTML(jsonml.shift())); + } + + for (var a in attributes) { + tagAttrs += attributes[a] == null ? ' ' + a : ' ' + a + '="' + escape(String(attributes[a]), true) + '"'; + } + + // be careful about adding whitespace here for inline elements + if (tag === '!') { + return ''; + } else if (tag in singletons) { + return '<' + tag + tagAttrs + ' />'; + } else { + return '<' + tag + tagAttrs + '>' + content.join('') + ''; + } + } + + module.exports = { + reIndent: reIndent, + toHTML: toHTML, + escape: escape + }; + +/***/ }, +/* 3 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var re = __webpack_require__(4); + var ribbon = __webpack_require__(5); + + re.pattern.html_id = '[a-zA-Z][a-zA-Z\\d:]*'; + re.pattern.html_attr = '(?:"[^"]+"|\'[^\']+\'|[^>\\s]+)'; + + var reAttr = re.compile(/^\s*([^=\s]+)(?:\s*=\s*("[^"]+"|'[^']+'|[^>\s]+))?/); + var reComment = re.compile(/^/, 's'); + var reEndTag = re.compile(/^<\/([:html_id:])([^>]*)>/); + var reTag = re.compile(/^<([:html_id:])((?:\s[^=\s\/]+(?:\s*=\s*[:html_attr:])?)+)?\s*(\/?)>(\n*)/); + var reHtmlTagBlock = re.compile(/^\s*<([:html_id:](?::[a-zA-Z\d]+)*)((?:\s[^=\s\/]+(?:\s*=\s*[:html_attr:])?)+)?\s*(\/?)>(\n*)/); + + // area, base, basefont, bgsound, br, col, command, embed, frame, hr, + // img, input, keygen, link, meta, param, source, track or wbr + var singletons = { + br: 1, + hr: 1, + img: 1, + link: 1, + meta: 1, + wbr: 1, + area: 1, + param: 1, + input: 1, + option: 1, + base: 1, + col: 1 + }; + + function allowAll() { + return true; + } + + function testComment(src) { + return reComment.exec(src); + } + + function testOpenTagBlock(src) { + return reHtmlTagBlock.exec(src); + } + + function testOpenTag(src) { + return reTag.exec(src); + } + + function testCloseTag(src) { + return reEndTag.exec(src); + } + + function parseHtmlAttr(attrSrc) { + // parse ATTR and add to element + var attr = {}; + var m = void 0; + while (m = reAttr.exec(attrSrc)) { + attr[m[1]] = typeof m[2] === 'string' ? m[2].replace(/^(["'])(.*)\1$/, '$2') : null; + attrSrc = attrSrc.slice(m[0].length); + } + return attr; + } + + // This "indesciminately" parses HTML text into a list of JSON-ML element + // No steps are taken however to prevent things like

- user can still create nonsensical but "well-formed" markup + function parseHtml(src, whitelistTags) { + var root = []; + var list = root; + var _stack = []; + var oktag = whitelistTags ? function (tag) { + return tag in whitelistTags; + } : allowAll; + var m = void 0; + var tag = void 0; + + src = typeof src === 'string' ? ribbon(src) : src; + // loop + do { + // comment + if ((m = testComment(src)) && oktag('!')) { + src.advance(m[0]); + list.push(['!', m[1]]); + } + + // end tag + else if ((m = testCloseTag(src)) && oktag(m[1])) { + tag = m[1]; + if (_stack.length) { + for (var i = _stack.length - 1; i >= 0; i--) { + var head = _stack[i]; + if (head[0] === tag) { + _stack.splice(i); + list = _stack[_stack.length - 1] || root; + break; + } + } + } + src.advance(m[0]); + } + + // open/void tag + else if ((m = testOpenTag(src)) && oktag(m[1])) { + src.advance(m[0]); + tag = m[1]; + var single = m[3] || m[1] in singletons; + var tail = m[4]; + var element = [tag]; + + // attributes + if (m[2]) { + element.push(parseHtmlAttr(m[2])); + } + + // single tag + if (single) { + // let us add the element and continue our quest... + list.push(element); + if (tail) { + list.push(tail); + } + } + // open tag + else { + if (tail) { + element.push(tail); + } + + // TODO: some things auto close other things: ,
  • ,

    , + // if ( tag === 'p' && _stack.length ) { + // var seek = /^(p)$/; + // for (var i=_stack.length-1; i>=0; i--) { + // var head = _stack[i]; + // if ( seek.test( head[0] ) /* === tag */ ) { + // //src.advance( m[0] ); + // _stack.splice( i ); + // list = _stack[i] || root; + // } + // } + // } + + // TODO: some elements can move parser into "text" mode + // style, xmp, iframe, noembed, noframe, textarea, title, script, noscript, plaintext + // if ( /^(script)$/.test( tag ) ) { } + + _stack.push(element); + list.push(element); + list = element; + } + } + // text content + else { + // no match, move by all "uninteresting" chars + m = /([^<]+|[^\0])/.exec(src); + if (m) { + list.push(m[0]); + } + src.advance(m ? m[0].length || 1 : 1); + } + } while (src.valueOf()); + + return root; + } + + module.exports = { + singletons: singletons, + parseHtml: parseHtml, + parseHtmlAttr: parseHtmlAttr, + testCloseTag: testCloseTag, + testOpenTagBlock: testOpenTagBlock, + testOpenTag: testOpenTag, + testComment: testComment + }; + +/***/ }, +/* 4 */ +/***/ function(module, exports) { + + 'use strict'; + + /* + ** Regular Expression helper methods + ** + ** This provides the `re` object, which contains several helper + ** methods for working with big regular expressions (soup). + ** + */ + + var _cache = {}; + + var re = module.exports = { + + pattern: { + 'punct': '[!-/:-@\\[\\\\\\]-`{-~]', + 'space': '\\s' + }, + + escape: function escape(src) { + return src.replace(/[\-\[\]\{\}\(\)\*\+\?\.,\\\^\$\|#\s]/g, '\\$&'); + }, + + collapse: function collapse(src) { + return src.replace(/(?:#.*?(?:\n|$))/g, '').replace(/\s+/g, ''); + }, + + expandPatterns: function expandPatterns(src) { + // TODO: provide escape for patterns: \[:pattern:] ? + return src.replace(/\[:\s*(\w+)\s*:\]/g, function (m, k) { + var ex = re.pattern[k]; + if (ex) { + return re.expandPatterns(ex); + } else { + throw new Error('Pattern ' + m + ' not found in ' + src); + } + }); + }, + + isRegExp: function isRegExp(r) { + return Object.prototype.toString.call(r) === '[object RegExp]'; + }, + + compile: function compile(src, flags) { + if (re.isRegExp(src)) { + if (arguments.length === 1) { + // no flags arg provided, use the RegExp one + flags = (src.global ? 'g' : '') + (src.ignoreCase ? 'i' : '') + (src.multiline ? 'm' : ''); + } + src = src.source; + } + // don't do the same thing twice + var ckey = src + (flags || ''); + if (ckey in _cache) { + return _cache[ckey]; + } + // allow classes + var rx = re.expandPatterns(src); + // allow verbose expressions + if (flags && /x/.test(flags)) { + rx = re.collapse(rx); + } + // allow dotall expressions + if (flags && /s/.test(flags)) { + rx = rx.replace(/([^\\])\./g, '$1[^\\0]'); + } + // TODO: test if MSIE and add replace \s with [\s\u00a0] if it is? + // clean flags and output new regexp + flags = (flags || '').replace(/[^gim]/g, ''); + return _cache[ckey] = new RegExp(rx, flags); + } + + }; + +/***/ }, +/* 5 */ +/***/ function(module, exports) { + + 'use strict'; + + module.exports = function ribbon(feed) { + var org = String(feed); + var slot = null; + var pos = 0; + + return { + + save: function save() { + slot = pos; + }, + + load: function load() { + pos = slot; + feed = org.slice(pos); + this.$ = feed; + }, + + advance: function advance(n) { + pos += typeof n === 'string' ? n.length : n; + feed = org.slice(pos); + this.$ = feed; + return feed; + }, + + lookbehind: function lookbehind(nchars) { + nchars = nchars == null ? 1 : nchars; + return org.slice(pos - nchars, pos); + }, + + startsWith: function startsWith(s) { + return feed.substring(0, s.length) === s; + }, + + valueOf: function valueOf() { + this.$ = feed; + return feed; + }, + + toString: function toString() { + this.$ = feed; + return feed; + } + + }; + }; + +/***/ }, +/* 6 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + /* + ** textile flow content parser + */ + var builder = __webpack_require__(7); + var ribbon = __webpack_require__(5); + var re = __webpack_require__(4); + var fixLinks = __webpack_require__(8); + + var _require = __webpack_require__(3); + + var parseHtml = _require.parseHtml; + var parseHtmlAttr = _require.parseHtmlAttr; + var singletons = _require.singletons; + var testComment = _require.testComment; + var testOpenTagBlock = _require.testOpenTagBlock; + + var _require2 = __webpack_require__(9); + + var parsePhrase = _require2.parsePhrase; + + var _require3 = __webpack_require__(10); + + var copyAttr = _require3.copyAttr; + var parseAttr = _require3.parseAttr; + + var _require4 = __webpack_require__(13); + + var testList = _require4.testList; + var parseList = _require4.parseList; + + var _require5 = __webpack_require__(14); + + var testDefList = _require5.testDefList; + var parseDefList = _require5.parseDefList; + + var _require6 = __webpack_require__(15); + + var testTable = _require6.testTable; + var parseTable = _require6.parseTable; + + var _require7 = __webpack_require__(12); + + var txblocks = _require7.txblocks; + var txlisthd = _require7.txlisthd; + var txattr = _require7.txattr; + + re.pattern.txblocks = txblocks; + re.pattern.txlisthd = txlisthd; + re.pattern.txattr = txattr; + + // HTML tags allowed in the document (root) level that trigger HTML parsing + var allowedBlocktags = { + 'p': 0, + 'hr': 0, + 'ul': 1, + 'ol': 0, + 'li': 0, + 'div': 1, + 'pre': 0, + 'object': 1, + 'script': 0, + 'noscript': 0, + 'blockquote': 1, + 'notextile': 1 + }; + + var reBlock = re.compile(/^([:txblocks:])/); + // const reBlockSE = re.compile( /^[:txblocks:]$/ ); + var reBlockNormal = re.compile(/^(.*?)($|\r?\n(?=[:txlisthd:])|\r?\n(?:\s*\n|$)+)/, 's'); + var reBlockExtended = re.compile(/^(.*?)($|\r?\n(?=[:txlisthd:])|\r?\n+(?=[:txblocks:][:txattr:]\.))/, 's'); + var reRuler = /^(\-\-\-+|\*\*\*+|___+)(\r?\n\s+|$)/; + var reLinkRef = re.compile(/^\[([^\]]+)\]((?:https?:\/\/|\/)\S+)(?:\s*\n|$)/); + var reFootnoteDef = /^fn\d+$/; + + function paragraph(s, tag, pba, linebreak, options) { + tag = tag || 'p'; + var out = []; + s.split(/(?:\r?\n){2,}/).forEach(function (bit, i) { + if (tag === 'p' && /^\s/.test(bit)) { + // no-paragraphs + // WTF?: Why does Textile not allow linebreaks in spaced lines + bit = bit.replace(/\r?\n[\t ]/g, ' ').trim(); + out = out.concat(parsePhrase(bit, options)); + } else { + if (linebreak && i) { + out.push(linebreak); + } + out.push(pba ? [tag, pba].concat(parsePhrase(bit, options)) : [tag].concat(parsePhrase(bit, options))); + } + }); + return out; + }; + + function parseFlow(src, options) { + var list = builder(); + + var linkRefs = void 0; + var m = void 0; + + src = ribbon(src.replace(/^( *\r?\n)+/, '')); + + // loop + while (src.valueOf()) { + src.save(); + + // link_ref -- this goes first because it shouldn't trigger a linebreak + if (m = reLinkRef.exec(src)) { + if (!linkRefs) { + linkRefs = {}; + } + src.advance(m[0]); + linkRefs[m[1]] = m[2]; + continue; + } + + // add linebreak + list.linebreak(); + + // named block + if (m = reBlock.exec(src)) { + src.advance(m[0]); + var blockType = m[0]; + var pba = parseAttr(src, blockType); + + if (pba) { + src.advance(pba[0]); + pba = pba[1]; + } + if (m = /^\.(\.?)(?:\s|(?=:))/.exec(src)) { + // FIXME: this whole copyAttr seems rather strange? + // slurp rest of block + var extended = !!m[1]; + var reBlockGlob = extended ? reBlockExtended : reBlockNormal; + m = reBlockGlob.exec(src.advance(m[0])); + src.advance(m[0]); + // bq | bc | notextile | pre | h# | fn# | p | ### + if (blockType === 'bq') { + var inner = m[1]; + if (m = /^:(\S+)\s+/.exec(inner)) { + if (!pba) { + pba = {}; + } + pba.cite = m[1]; + inner = inner.slice(m[0].length); + } + // RedCloth adds all attr to both: this is bad because it produces duplicate IDs + var par = paragraph(inner, 'p', copyAttr(pba, { 'cite': 1, 'id': 1 }), '\n', options); + list.add(['blockquote', pba, '\n'].concat(par).concat(['\n'])); + // FIXME: looks like .linebreak can work here + } else if (blockType === 'bc') { + var subPba = pba ? copyAttr(pba, { 'id': 1 }) : null; + list.add(['pre', pba, subPba ? ['code', subPba, m[1]] : ['code', m[1]]]); + } else if (blockType === 'notextile') { + list.merge(parseHtml(m[1])); + } else if (blockType === '###') { + // ignore the insides + } else if (blockType === 'pre') { + // I disagree with RedCloth, but agree with PHP here: + // "pre(foo#bar).. line1\n\nline2" prevents multiline preformat blocks + // ...which seems like the whole point of having an extended pre block? + list.add(['pre', pba, m[1]]); + } else if (reFootnoteDef.test(blockType)) { + // footnote + // Need to be careful: RedCloth fails "fn1(foo#m). footnote" -- it confuses the ID + var fnid = blockType.replace(/\D+/g, ''); + if (!pba) { + pba = {}; + } + pba.class = (pba['class'] ? pba['class'] + ' ' : '') + 'footnote'; + pba.id = 'fn' + fnid; + list.add(['p', pba, ['a', { 'href': '#fnr' + fnid }, ['sup', fnid]], ' '].concat(parsePhrase(m[1], options))); + } else { + // heading | paragraph + list.merge(paragraph(m[1], blockType, pba, '\n', options)); + } + continue; + } else { + src.load(); + } + } + + // HTML comment + if (m = testComment(src)) { + src.advance(m[0] + (/(?:\s*\n+)+/.exec(src) || [])[0]); + list.add(['!', m[1]]); + continue; + } + + // block HTML + if (m = testOpenTagBlock(src)) { + var tag = m[1]; + var single = m[3] || tag in singletons; + var tail = m[4]; + + // Unsurprisingly, all Textile implementations I have tested have trouble parsing simple HTML: + // + // "
    a\n
    b\n
    c\n
    d" + // + // I simply match them here as there is no way anyone is using nested HTML today, or if they + // are, then this will at least output less broken HTML as redundant tags will get quoted. + + // Is block tag? ... + if (tag in allowedBlocktags) { + src.advance(m[0]); + + var element = [tag]; + + if (m[2]) { + element.push(parseHtmlAttr(m[2])); + } + + // single tag + if (single) { + // let us add the element and continue our quest... + list.add(element); + continue; + } + // block + else { + // gulp up the rest of this block... + var reEndTag = re.compile('^(.*?)(\\s*)()(\\s*)', 's'); + if (m = reEndTag.exec(src)) { + src.advance(m[0]); + if (tag === 'pre') { + element.push(tail); + element = element.concat(parseHtml(m[1].replace(/(\r?\n)+$/, ''), { 'code': 1 })); + if (m[2]) { + element.push(m[2]); + } + list.add(element); + } else if (tag === 'notextile') { + element = parseHtml(m[1].trim()); + list.merge(element); + } else if (tag === 'script' || tag === 'noscript') { + element.push(tail + m[1]); + list.add(element); + } else { + // These strange (and unnecessary) linebreak tests are here to get the + // tests working perfectly. In reality, this doesn't matter one bit. + if (/\n/.test(tail)) { + element.push('\n'); + } + if (/\n/.test(m[1])) { + element = element.concat(parseFlow(m[1], options)); + } else { + element = element.concat(parsePhrase(m[1].replace(/^ +/, ''), options)); + } + if (/\n/.test(m[2])) { + element.push('\n'); + } + + list.add(element); + } + continue; + } + } + } + src.load(); + } + + // ruler + if (m = reRuler.exec(src)) { + src.advance(m[0]); + list.add(['hr']); + continue; + } + + // list + if (m = testList(src)) { + src.advance(m[0]); + list.add(parseList(m[0], options)); + continue; + } + + // definition list + if (m = testDefList(src)) { + src.advance(m[0]); + list.add(parseDefList(m[0], options)); + continue; + } + + // table + if (m = testTable(src)) { + src.advance(m[0]); + list.add(parseTable(m[1], options)); + continue; + } + + // paragraph + m = reBlockNormal.exec(src); + list.merge(paragraph(m[1], 'p', undefined, '\n', options)); + src.advance(m[0]); + } + + return linkRefs ? fixLinks(list.get(), linkRefs) : list.get(); + } + + exports.parseFlow = parseFlow; + +/***/ }, +/* 7 */ +/***/ function(module, exports) { + + 'use strict'; + + module.exports = function builder(initArr) { + var arr = Array.isArray(initArr) ? initArr : []; + + return { + add: function add(node) { + if (typeof node === 'string' && typeof arr[arr.length - 1] === 'string') { + // join if possible + arr[arr.length - 1] += node; + } else if (Array.isArray(node)) { + arr.push(node.filter(function (s) { + return s !== undefined; + })); + } else if (node) { + arr.push(node); + } + return this; + }, + + merge: function merge(arr) { + for (var i = 0, l = arr.length; i < l; i++) { + this.add(arr[i]); + } + return this; + }, + + linebreak: function linebreak() { + if (arr.length) { + this.add('\n'); + } + }, + + get: function get() { + return arr; + } + }; + }; + +/***/ }, +/* 8 */ +/***/ function(module, exports) { + + 'use strict'; + + var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; }; + + // recurse the tree and swap out any "href" attributes + // this uses the context as the replace dictionary so it can be fed to Array#map + module.exports = function fixLinks(ml, dict) { + if (Array.isArray(ml)) { + if (ml[0] === 'a') { + // found a link + var attr = ml[1]; + if ((typeof attr === 'undefined' ? 'undefined' : _typeof(attr)) === 'object' && 'href' in attr && attr.href in dict) { + attr.href = dict[attr.href]; + } + } + for (var i = 0, l = ml.length; i < l; i++) { + if (Array.isArray(ml[i])) { + fixLinks(ml[i], dict); + } + } + } + return ml; + }; + +/***/ }, +/* 9 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + /* textile inline parser */ + + var ribbon = __webpack_require__(5); + var builder = __webpack_require__(7); + var re = __webpack_require__(4); + + var _require = __webpack_require__(10); + + var parseAttr = _require.parseAttr; + + var _require2 = __webpack_require__(11); + + var parseGlyph = _require2.parseGlyph; + + var _require3 = __webpack_require__(3); + + var parseHtmlAttr = _require3.parseHtmlAttr; + var singletons = _require3.singletons; + var testComment = _require3.testComment; + var testOpenTag = _require3.testOpenTag; + + var _require4 = __webpack_require__(12); + + var ucaps = _require4.ucaps; + var txattr = _require4.txattr; + var txcite = _require4.txcite; + + re.pattern.txattr = txattr; + re.pattern.txcite = txcite; + re.pattern.ucaps = ucaps; + + var phraseConvert = { + '*': 'strong', + '**': 'b', + '??': 'cite', + '_': 'em', + '__': 'i', + '-': 'del', + '%': 'span', + '+': 'ins', + '~': 'sub', + '^': 'sup', + '@': 'code' + }; + + var rePhrase = /^([\[\{]?)(__?|\*\*?|\?\?|[\-\+\^~@%])/; + var reImage = re.compile(/^!(?!\s)([:txattr:](?:\.[^\n\S]|\.(?:[^\.\/]))?)([^!\s]+?) ?(?:\(((?:[^\(\)]+|\([^\(\)]+\))+)\))?!(?::([^\s]+?(?=[!-\.:-@\[\\\]-`{-~](?:$|\s)|\s|$)))?/); + var reImageFenced = re.compile(/^\[!(?!\s)([:txattr:](?:\.[^\n\S]|\.(?:[^\.\/]))?)([^!\s]+?) ?(?:\(((?:[^\(\)]+|\([^\(\)]+\))+)\))?!(?::([^\s]+?(?=[!-\.:-@\[\\\]-`{-~](?:$|\s)|\s|$)))?\]/); + // NB: there is an exception in here to prevent matching "TM)" + var reCaps = re.compile(/^((?!TM\)|tm\))[[:ucaps:]](?:[[:ucaps:]\d]{1,}(?=\()|[[:ucaps:]\d]{2,}))(?:\((.*?)\))?(?=\W|$)/); + var reLink = re.compile(/^"(?!\s)((?:[^\n"]|"(?![\s:])[^\n"]+"(?!:))+)"[:txcite:]/); + var reLinkFenced = /^\["([^\n]+?)":((?:\[[a-z0-9]*\]|[^\]])+)\]/; + var reLinkTitle = /\s*\(((?:\([^\(\)]*\)|[^\(\)])+)\)$/; + var reFootnote = /^\[(\d+)(!?)\]/; + + function parsePhrase(src, options) { + src = ribbon(src); + + var list = builder(); + var m = void 0; + var pba = void 0; + + // loop + do { + src.save(); + + // linebreak -- having this first keeps it from messing to much with other phrases + if (src.startsWith('\r\n')) { + src.advance(1); // skip cartridge returns + } + if (src.startsWith('\n')) { + src.advance(1); + if (options.breaks) { + list.add(['br']); + } + list.add('\n'); + continue; + } + + // inline notextile + if (m = /^==(.*?)==/.exec(src)) { + src.advance(m[0]); + list.add(m[1]); + continue; + } + + // lookbehind => /([\s>.,"'?!;:])$/ + var behind = src.lookbehind(1); + var boundary = !behind || /^[\s>.,"'?!;:()]$/.test(behind); + // FIXME: need to test right boundary for phrases as well + if ((m = rePhrase.exec(src)) && (boundary || m[1])) { + src.advance(m[0]); + var tok = m[2]; + var fence = m[1]; + var phraseType = phraseConvert[tok]; + var code = phraseType === 'code'; + + if (pba = !code && parseAttr(src, phraseType, tok)) { + src.advance(pba[0]); + pba = pba[1]; + } + // FIXME: if we can't match the fence on the end, we should output fence-prefix as normal text + // seek end + var mMid = void 0; + var mEnd = void 0; + if (fence === '[') { + mMid = '^(.*?)'; + mEnd = '(?:])'; + } else if (fence === '{') { + mMid = '^(.*?)'; + mEnd = '(?:})'; + } else { + var t1 = re.escape(tok.charAt(0)); + mMid = code ? '^(\\S+|\\S+.*?\\S)' : '^([^\\s' + t1 + ']+|[^\\s' + t1 + '].*?\\S(' + t1 + '*))'; + mEnd = '(?=$|[\\s.,"\'!?;:()«»„“”‚‘’])'; + } + var rx = re.compile(mMid + '(' + re.escape(tok) + ')' + mEnd); + if ((m = rx.exec(src)) && m[1]) { + src.advance(m[0]); + if (code) { + list.add([phraseType, m[1]]); + } else { + list.add([phraseType, pba].concat(parsePhrase(m[1], options))); + } + continue; + } + // else + src.load(); + } + + // image + if ((m = reImage.exec(src)) || (m = reImageFenced.exec(src))) { + src.advance(m[0]); + + pba = m[1] && parseAttr(m[1], 'img'); + var attr = pba ? pba[1] : { 'src': '' }; + var img = ['img', attr]; + attr.src = m[2]; + attr.alt = m[3] ? attr.title = m[3] : ''; + + if (m[4]) { + // +cite causes image to be wraped with a link (or link_ref)? + // TODO: support link_ref for image cite + img = ['a', { 'href': m[4] }, img]; + } + list.add(img); + continue; + } + + // html comment + if (m = testComment(src)) { + src.advance(m[0]); + list.add(['!', m[1]]); + continue; + } + // html tag + // TODO: this seems to have a lot of overlap with block tags... DRY? + if (m = testOpenTag(src)) { + src.advance(m[0]); + var tag = m[1]; + var single = m[3] || m[1] in singletons; + var element = [tag]; + var tail = m[4]; + if (m[2]) { + element.push(parseHtmlAttr(m[2])); + } + if (single) { + // single tag + list.add(element).add(tail); + continue; + } else { + // need terminator + // gulp up the rest of this block... + var reEndTag = re.compile('^(.*?)()', 's'); + if (m = reEndTag.exec(src)) { + src.advance(m[0]); + if (tag === 'code') { + element.push(tail, m[1]); + } else if (tag === 'notextile') { + list.merge(parsePhrase(m[1], options)); + continue; + } else { + element = element.concat(parsePhrase(m[1], options)); + } + list.add(element); + continue; + } + // end tag is missing, treat tag as normal text... + } + src.load(); + } + + // footnote + if ((m = reFootnote.exec(src)) && /\S/.test(behind)) { + src.advance(m[0]); + list.add(['sup', { 'class': 'footnote', 'id': 'fnr' + m[1] }, m[2] === '!' ? m[1] // "!" suppresses the link + : ['a', { href: '#fn' + m[1] }, m[1]]]); + continue; + } + + // caps / abbr + if (m = reCaps.exec(src)) { + src.advance(m[0]); + var caps = ['span', { 'class': 'caps' }, m[1]]; + if (m[2]) { + // FIXME: use , not acronym! + caps = ['acronym', { 'title': m[2] }, caps]; + } + list.add(caps); + continue; + } + + // links + if (boundary && (m = reLink.exec(src)) || (m = reLinkFenced.exec(src))) { + src.advance(m[0]); + var title = m[1].match(reLinkTitle); + var inner = title ? m[1].slice(0, m[1].length - title[0].length) : m[1]; + if (pba = parseAttr(inner, 'a')) { + inner = inner.slice(pba[0]); + pba = pba[1]; + } else { + pba = {}; + } + if (title && !inner) { + inner = title[0]; + title = ''; + } + pba.href = m[2]; + if (title) { + pba.title = title[1]; + } + list.add(['a', pba].concat(parsePhrase(inner.replace(/^(\.?\s*)/, ''), options))); + continue; + } + + // no match, move by all "uninteresting" chars + m = /([a-zA-Z0-9,.':]+|[ \f\r\t\v\xA0\u2028\u2029]+|[^\0])/.exec(src); + if (m) { + list.add(m[0]); + } + src.advance(m ? m[0].length || 1 : 1); + } while (src.valueOf()); + + return list.get().map(parseGlyph); + } + + exports.parsePhrase = parsePhrase; + +/***/ }, +/* 10 */ +/***/ function(module, exports) { + + 'use strict'; + + var reClassid = /^\(([^\(\)\n]+)\)/; + var rePaddingL = /^(\(+)/; + var rePaddingR = /^(\)+)/; + var reAlignBlock = /^(<>|<|>|=)/; + var reAlignImg = /^(<|>|=)/; + var reVAlign = /^(~|\^|\-)/; + var reColSpan = /^\\(\d+)/; + var reRowSpan = /^\/(\d+)/; + var reStyles = /^\{([^\}]*)\}/; + var reCSS = /^\s*([^:\s]+)\s*:\s*(.+)\s*$/; + var reLang = /^\[([^\[\]\n]+)\]/; + + var pbaAlignLookup = { + '<': 'left', + '=': 'center', + '>': 'right', + '<>': 'justify' + }; + + var pbaVAlignLookup = { + '~': 'bottom', + '^': 'top', + '-': 'middle' + }; + + function copyAttr(s, blacklist) { + if (!s) { + return undefined; + } + var d = {}; + for (var k in s) { + if (k in s && (!blacklist || !(k in blacklist))) { + d[k] = s[k]; + } + } + return d; + } + + function testBlock(name) { + // "in" test would be better but what about fn#.? + return (/^(?:table|t[dh]|t(?:foot|head|body)|b[qc]|div|notextile|pre|h[1-6]|fn\\d+|p|###)$/.test(name) + ); + } + + /* + The attr bit causes massive problems for span elements when parentheses are used. + Parentheses are a total mess and, unsurprisingly, cause trip-ups: + + RC: `_{display:block}(span) span (span)_` -> `(span) span (span)` + PHP: `_{display:block}(span) span (span)_` -> `(span) span (span)` + + PHP and RC seem to mostly solve this by not parsing a final attr parens on spans if the + following character is a non-space. I've duplicated that: Class/ID is not matched on spans + if it is followed by `endToken` or . + + Lang is not matched here if it is followed by the end token. Theoretically I could limit the lang + attribute to /^\[[a-z]{2+}(\-[a-zA-Z0-9]+)*\]/ because Textile is layered on top of HTML which + only accepts valid BCP 47 language tags, but who knows what atrocities are being preformed + out there in the real world. So this attempts to emulate the other libraries. + */ + function parseAttr(input, element, endToken) { + input = String(input); + if (!input || element === 'notextile') { + return undefined; + } + + var m = void 0; + var st = {}; + var o = { 'style': st }; + var remaining = input; + + var isBlock = testBlock(element); + var isImg = element === 'img'; + var isList = element === 'li'; + var isPhrase = !isBlock && !isImg && element !== 'a'; + var reAlign = isImg ? reAlignImg : reAlignBlock; + + do { + if (m = reStyles.exec(remaining)) { + m[1].split(';').forEach(function (p) { + var d = p.match(reCSS); + if (d) { + st[d[1]] = d[2]; + } + }); + remaining = remaining.slice(m[0].length); + continue; + } + + if (m = reLang.exec(remaining)) { + var rm = remaining.slice(m[0].length); + if (!rm && isPhrase || endToken && endToken === rm.slice(0, endToken.length)) { + m = null; + } else { + o['lang'] = m[1]; + remaining = remaining.slice(m[0].length); + } + continue; + } + + if (m = reClassid.exec(remaining)) { + var _rm = remaining.slice(m[0].length); + if (!_rm && isPhrase || endToken && (_rm[0] === ' ' || endToken === _rm.slice(0, endToken.length))) { + m = null; + } else { + var bits = m[1].split('#'); + if (bits[0]) { + o.class = bits[0]; + } + if (bits[1]) { + o.id = bits[1]; + } + remaining = _rm; + } + continue; + } + + if (isBlock || isList) { + if (m = rePaddingL.exec(remaining)) { + st['padding-left'] = m[1].length + 'em'; + remaining = remaining.slice(m[0].length); + continue; + } + if (m = rePaddingR.exec(remaining)) { + st['padding-right'] = m[1].length + 'em'; + remaining = remaining.slice(m[0].length); + continue; + } + } + + // only for blocks: + if (isImg || isBlock || isList) { + if (m = reAlign.exec(remaining)) { + var align = pbaAlignLookup[m[1]]; + if (isImg) { + o['align'] = align; + } else { + st['text-align'] = align; + } + remaining = remaining.slice(m[0].length); + continue; + } + } + + // only for table cells + if (element === 'td' || element === 'tr') { + if (m = reVAlign.exec(remaining)) { + st['vertical-align'] = pbaVAlignLookup[m[1]]; + remaining = remaining.slice(m[0].length); + continue; + } + } + if (element === 'td') { + if (m = reColSpan.exec(remaining)) { + o['colspan'] = m[1]; + remaining = remaining.slice(m[0].length); + continue; + } + if (m = reRowSpan.exec(remaining)) { + o['rowspan'] = m[1]; + remaining = remaining.slice(m[0].length); + continue; + } + } + } while (m); + + // collapse styles + var s = []; + for (var v in st) { + s.push(v + ':' + st[v]); + } + if (s.length) { + o.style = s.join(';'); + } else { + delete o.style; + } + + return remaining === input ? undefined : [input.length - remaining.length, o]; + } + + module.exports = { + copyAttr: copyAttr, + parseAttr: parseAttr + }; + +/***/ }, +/* 11 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + /* textile glyph parser */ + + var re = __webpack_require__(4); + + var reApostrophe = /(\w)'(\w)/g; + var reArrow = /([^\-]|^)->/; + var reClosingDQuote = re.compile(/([^\s\[\(])"(?=$|\s|[:punct:])/g); + var reClosingSQuote = re.compile(/([^\s\[\(])'(?=$|\s|[:punct:])/g); + var reCopyright = /(\b ?|\s|^)(?:\(C\)|\[C\])/gi; + var reDimsign = /([\d\.,]+['"]? ?)x( ?)(?=[\d\.,]['"]?)/g; + var reDoublePrime = re.compile(/(\d*[\.,]?\d+)"(?=\s|$|[:punct:])/g); + var reEllipsis = /([^.]?)\.{3}/g; + var reEmdash = /(^|[\s\w])--([\s\w]|$)/g; + var reEndash = / - /g; + var reOpenDQuote = /"/g; + var reOpenSQuote = /'/g; + var reRegistered = /(\b ?|\s|^)(?:\(R\)|\[R\])/gi; + var reSinglePrime = re.compile(/(\d*[\.,]?\d+)'(?=\s|$|[:punct:])/g); + var reTrademark = /(\b ?|\s|^)(?:\((?:TM|tm)\)|\[(?:TM|tm)\])/g; + + exports.parseGlyph = function parseGlyph(src) { + if (typeof src !== 'string') { + return src; + } + // NB: order is important here ... + return src.replace(reArrow, '$1→').replace(reDimsign, '$1×$2').replace(reEllipsis, '$1…').replace(reEmdash, '$1—$2').replace(reEndash, ' – ').replace(reTrademark, '$1™').replace(reRegistered, '$1®').replace(reCopyright, '$1©') + // double quotes + .replace(reDoublePrime, '$1″').replace(reClosingDQuote, '$1”').replace(reOpenDQuote, '“') + // single quotes + .replace(reSinglePrime, '$1′').replace(reApostrophe, '$1’$2').replace(reClosingSQuote, '$1’').replace(reOpenSQuote, '‘') + // fractions and degrees + .replace(/[\(\[]1\/4[\]\)]/, '¼').replace(/[\(\[]1\/2[\]\)]/, '½').replace(/[\(\[]3\/4[\]\)]/, '¾').replace(/[\(\[]o[\]\)]/, '°').replace(/[\(\[]\+\/\-[\]\)]/, '±'); + }; + +/***/ }, +/* 12 */ +/***/ function(module, exports) { + + 'use strict'; + + /* eslint camelcase: 0 */ + + exports.txblocks = '(?:b[qc]|div|notextile|pre|h[1-6]|fn\\d+|p|###)'; + + exports.ucaps = 'A-Z' + + // Latin extended À-Þ + 'À-ÖØ-Þ' + + // Latin caps with embelishments and ligatures... + 'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮİIJĴĶĹĻĽĿ' + 'ŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŸŹŻŽ' + 'ƁƂƄƆƇƉ-ƋƎ-ƑƓƔƖ-ƘƜƝƟƠƢƤƦƧƩƬƮƯƱ-ƳƵƷƸƼ' + 'DŽLJNJǍǏǑǓǕǗǙǛǞǠǢǤǦǨǪǬǮDZǴǶ-ǸǺǼǾ' + 'ȀȂȄȆȈȊȌȎȐȒȔȖȘȚȜȞȠȢȤȦȨȪȬȮȰȲȺȻȽȾ' + 'ɁɃ-ɆɈɊɌɎ' + 'ḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀ' + 'ṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾ' + 'ẀẂẄẆẈẊẌẎẐẒẔẞẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾ' + 'ỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸỺỼỾ' + 'ⱠⱢ-ⱤⱧⱩⱫⱭ-ⱰⱲⱵⱾⱿ' + 'ꜢꜤꜦꜨꜪꜬꜮꜲꜴꜶꜸꜺꜼꜾ' + 'ꝀꝂꝄꝆꝈꝊꝌꝎꝐꝒꝔꝖꝘꝚꝜꝞꝠꝢꝤꝦꝨꝪꝬꝮꝹꝻꝽꝾ' + 'ꞀꞂꞄꞆꞋꞍꞐꞒꞠꞢꞤꞦꞨꞪ'; + + exports.txcite = ':((?:[^\\s()]|\\([^\\s()]+\\)|[()])+?)(?=[!-\\.:-@\\[\\\\\\]-`{-~]+(?:$|\\s)|$|\\s)'; + + var attr_class = exports.attr_class = '\\([^\\)]+\\)'; + var attr_style = exports.attr_style = '\\{[^\\}]+\\}'; + var attr_lang = exports.attr_lang = '\\[[^\\[\\]]+\\]'; + var attr_align = exports.attr_align = '(?:<>|<|>|=)'; + var attr_pad = exports.attr_pad = '[\\(\\)]+'; + + var txattr = exports.txattr = '(?:' + attr_class + '|' + attr_style + '|' + attr_lang + '|' + attr_align + '|' + attr_pad + ')*'; + + exports.txlisthd = '[\\t ]*[\\#\\*]*(\\*|\\#(?:_|\\d+)?)' + txattr + '(?: \\S|\\.\\s*(?=\\S|\\n))'; + +/***/ }, +/* 13 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + /* textile list parser */ + var ribbon = __webpack_require__(5); + var re = __webpack_require__(4); + var merge = __webpack_require__(1); + + var _require = __webpack_require__(10); + + var parseAttr = _require.parseAttr; + + var _require2 = __webpack_require__(9); + + var parsePhrase = _require2.parsePhrase; + + var _require3 = __webpack_require__(12); + + var txlisthd = _require3.txlisthd; + + re.pattern.txlisthd = txlisthd; + var reList = re.compile(/^((?:[:txlisthd:][^\0]*?(?:\r?\n|$))+)(\s*\n|$)/, 's'); + var reItem = re.compile(/^([#\*]+)([^\0]+?)(\n(?=[:txlisthd:])|$)/, 's'); + + function listPad(n) { + var s = '\n'; + while (n--) { + s += '\t'; + } + return s; + } + + function testList(src) { + return reList.exec(src); + } + + function parseList(src, options) { + src = ribbon(src.replace(/(^|\r?\n)[\t ]+/, '$1')); + + var stack = []; + var currIndex = {}; + var lastIndex = options._lst || {}; + var itemIndex = 0; + var listAttr = void 0; + var m = void 0; + var n = void 0; + var s = void 0; + + while (m = reItem.exec(src)) { + var item = ['li']; + var destLevel = m[1].length; + var type = m[1].substr(-1) === '#' ? 'ol' : 'ul'; + var newLi = null; + var lst = void 0; + var par = void 0; + var pba = void 0; + var r = void 0; + + // list starts and continuations + if (n = /^(_|\d+)/.exec(m[2])) { + itemIndex = isFinite(n[1]) ? parseInt(n[1], 10) : lastIndex[destLevel] || currIndex[destLevel] || 1; + m[2] = m[2].slice(n[1].length); + } + + if (pba = parseAttr(m[2], 'li')) { + m[2] = m[2].slice(pba[0]); + pba = pba[1]; + } + + // list control + if (/^\.\s*$/.test(m[2])) { + listAttr = pba || {}; + src.advance(m[0]); + continue; + } + + // create nesting until we have correct level + while (stack.length < destLevel) { + // list always has an attribute object, this simplifies first-pba resolution + lst = [type, {}, listPad(stack.length + 1), newLi = ['li']]; + par = stack[stack.length - 1]; + if (par) { + par.li.push(listPad(stack.length)); + par.li.push(lst); + } + stack.push({ + ul: lst, + li: newLi, + // count attributes's found per list + att: 0 + }); + currIndex[stack.length] = 1; + } + + // remove nesting until we have correct level + while (stack.length > destLevel) { + r = stack.pop(); + r.ul.push(listPad(stack.length)); + // lists have a predictable structure - move pba from listitem to list + if (r.att === 1 && !r.ul[3][1].substr) { + merge(r.ul[1], r.ul[3].splice(1, 1)[0]); + } + } + + // parent list + par = stack[stack.length - 1]; + + if (itemIndex) { + par.ul[1].start = itemIndex; + currIndex[destLevel] = itemIndex; + // falsy prevents this from fireing until it is set again + itemIndex = 0; + } + if (listAttr) { + // "more than 1" prevent attribute transfers on list close + par.att = 9; + merge(par.ul[1], listAttr); + listAttr = null; + } + + if (!newLi) { + par.ul.push(listPad(stack.length), item); + par.li = item; + } + if (pba) { + par.li.push(pba); + par.att++; + } + Array.prototype.push.apply(par.li, parsePhrase(m[2].trim(), options)); + + src.advance(m[0]); + currIndex[destLevel] = (currIndex[destLevel] || 0) + 1; + } + + // remember indexes for continuations next time + options._lst = currIndex; + + while (stack.length) { + s = stack.pop(); + s.ul.push(listPad(stack.length)); + // lists have a predictable structure - move pba from listitem to list + if (s.att === 1 && !s.ul[3][1].substr) { + merge(s.ul[1], s.ul[3].splice(1, 1)[0]); + } + } + + return s.ul; + } + + module.exports = { + testList: testList, + parseList: parseList + }; + +/***/ }, +/* 14 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + /* definitions list parser */ + + var ribbon = __webpack_require__(5); + + var reDeflist = /^((?:- (?:[^\n]\n?)+?)+:=(?: *\n[^\0]+?=:(?:\n|$)|(?:[^\0]+?(?:$|\n(?=\n|- )))))+/; + var reItem = /^((?:- (?:[^\n]\n?)+?)+):=( *\n[^\0]+?=:\s*(?:\n|$)|(?:[^\0]+?(?:$|\n(?=\n|- ))))/; + + function testDefList(src) { + return reDeflist.exec(src); + } + + function parseDefList(src, options) { + src = ribbon(src.trim()); + + // late loading to get around the lack of non-circular-dependency support in RequireJS + var parsePhrase = __webpack_require__(9).parsePhrase; + var parseFlow = __webpack_require__(6).parseFlow; + + var deflist = ['dl', '\n']; + var terms = void 0; + var def = void 0; + var m = void 0; + + while (m = reItem.exec(src)) { + // add terms + terms = m[1].split(/(?:^|\n)\- /).slice(1); + while (terms.length) { + deflist.push('\t', ['dt'].concat(parsePhrase(terms.shift().trim(), options)), '\n'); + } + // add definitions + def = m[2].trim(); + deflist.push('\t', ['dd'].concat(/=:$/.test(def) ? parseFlow(def.slice(0, -2).trim(), options) : parsePhrase(def, options)), '\n'); + src.advance(m[0]); + } + return deflist; + } + + exports.testDefList = testDefList; + exports.parseDefList = parseDefList; + +/***/ }, +/* 15 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + /* textile table parser */ + + var re = __webpack_require__(4); + var merge = __webpack_require__(1); + var ribbon = __webpack_require__(5); + + var _require = __webpack_require__(10); + + var parseAttr = _require.parseAttr; + + var _require2 = __webpack_require__(9); + + var parsePhrase = _require2.parsePhrase; + + var _require3 = __webpack_require__(2); + + var reIndent = _require3.reIndent; + + var _require4 = __webpack_require__(12); + + var txattr = _require4.txattr; + + re.pattern.txattr = txattr; + + var reTable = re.compile(/^((?:table[:txattr:]\.(?:\s(.+?))\s*\n)?(?:(?:[:txattr:]\.[^\n\S]*)?\|.*?\|[^\n\S]*(?:\n|$))+)([^\n\S]*\n)?/, 's'); + var reHead = /^table(_?)([^\n]*?)\.(?:[ \t](.+?))?\s*\n/; + var reRow = re.compile(/^(?:\|([~\^\-][:txattr:])\.\s*\n)?([:txattr:]\.[^\n\S]*)?\|(.*?)\|[^\n\S]*(\n|$)/, 's'); + var reCaption = /^\|=([^\n+]*)\n/; + var reColgroup = /^\|:([^\n+]*)\|[\r\t ]*\n/; + var reRowgroup = /^\|([\^\-~])([^\n+]*)\.[ \t\r]*\n/; + + var charToTag = { + '^': 'thead', + '~': 'tfoot', + '-': 'tbody' + }; + + function parseColgroup(src) { + var colgroup = ['colgroup', {}]; + src.split('|').forEach(function (s, isCol) { + var col = isCol ? {} : colgroup[1]; + var d = s.trim(); + var m = void 0; + if (d) { + if (m = /^\\(\d+)/.exec(d)) { + col.span = +m[1]; + d = d.slice(m[0].length); + } + if (m = parseAttr(d, 'col')) { + merge(col, m[1]); + d = d.slice(m[0]); + } + if (m = /\b\d+\b/.exec(d)) { + col.width = +m[0]; + } + } + if (isCol) { + colgroup.push('\n\t\t', ['col', col]); + } + }); + return colgroup.concat(['\n\t']); + } + + function testTable(src) { + return reTable.exec(src); + } + + function parseTable(src, options) { + src = ribbon(src.trim()); + + var rowgroups = []; + var colgroup = void 0; + var caption = void 0; + var tAttr = {}; + var tCurr = void 0; + var row = void 0; + var inner = void 0; + var pba = void 0; + var more = void 0; + var m = void 0; + var extended = 0; + + var setRowGroup = function setRowGroup(type, pba) { + tCurr = [type, pba || {}]; + rowgroups.push(tCurr); + }; + + if (m = reHead.exec(src)) { + // parse and apply table attr + src.advance(m[0]); + pba = parseAttr(m[2], 'table'); + if (pba) { + merge(tAttr, pba[1]); + } + if (m[3]) { + tAttr.summary = m[3]; + } + } + + // caption + if (m = reCaption.exec(src)) { + caption = ['caption']; + if (pba = parseAttr(m[1], 'caption')) { + caption.push(pba[1]); + m[1] = m[1].slice(pba[0]); + } + if (/\./.test(m[1])) { + // mandatory "." + caption.push(m[1].slice(1).replace(/\|\s*$/, '').trim()); + extended++; + src.advance(m[0]); + } else { + caption = null; + } + } + + do { + // colgroup + if (m = reColgroup.exec(src)) { + colgroup = parseColgroup(m[1]); + extended++; + } + // "rowgroup" (tbody, thead, tfoot) + else if (m = reRowgroup.exec(src)) { + // PHP allows any amount of these in any order + // and simply translates them straight through + // the same is done here. + var tag = charToTag[m[1]] || 'tbody'; + pba = parseAttr(m[2] + ' ', tag); + setRowGroup(tag, pba && pba[1]); + extended++; + } + // row + else if (m = reRow.exec(src)) { + if (!tCurr) { + setRowGroup('tbody'); + } + + row = ['tr']; + + if (m[2] && (pba = parseAttr(m[2], 'tr'))) { + // FIXME: requires "\.\s?" -- else what ? + row.push(pba[1]); + } + + tCurr.push('\n\t\t', row); + inner = ribbon(m[3]); + + do { + inner.save(); + + // cell loop + var th = inner.startsWith('_'); + var cell = [th ? 'th' : 'td']; + if (th) { + inner.advance(1); + } + + pba = parseAttr(inner, 'td'); + if (pba) { + inner.advance(pba[0]); + cell.push(pba[1]); // FIXME: don't do this if next text fails + } + + if (pba || th) { + var p = /^\.\s*/.exec(inner); + if (p) { + inner.advance(p[0]); + } else { + cell = ['td']; + inner.load(); + } + } + + var mx = /^(==.*?==|[^\|])*/.exec(inner); + cell = cell.concat(parsePhrase(mx[0], options)); + row.push('\n\t\t\t', cell); + more = inner.valueOf().charAt(mx[0].length) === '|'; + inner.advance(mx[0].length + 1); + } while (more); + + row.push('\n\t\t'); + } + // + if (m) { + src.advance(m[0]); + } + } while (m); + + // assemble table + var table = ['table', tAttr]; + if (extended) { + if (caption) { + table.push('\n\t', caption); + } + if (colgroup) { + table.push('\n\t', colgroup); + } + rowgroups.forEach(function (tbody) { + table.push('\n\t', tbody.concat(['\n\t'])); + }); + } else { + table = table.concat(reIndent(rowgroups[0].slice(2), -1)); + } + + table.push('\n'); + return table; + } + + module.exports = { + parseColgroup: parseColgroup, + parseTable: parseTable, + testTable: testTable + }; + +/***/ } +/******/ ]) +}); +; +//# sourceMappingURL=textile.js.map \ No newline at end of file diff --git a/dist/textile.js.map b/dist/textile.js.map new file mode 100644 index 0000000..6012816 --- /dev/null +++ b/dist/textile.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///webpack/bootstrap 75feac9fe5b945b13943","webpack:///./src/index.js","webpack:///./src/merge.js","webpack:///./src/jsonml.js","webpack:///./src/html.js","webpack:///./src/re.js","webpack:///./src/ribbon.js","webpack:///./src/textile/flow.js","webpack:///./src/builder.js","webpack:///./src/fixlinks.js","webpack:///./src/textile/phrase.js","webpack:///./src/textile/attr.js","webpack:///./src/textile/glyph.js","webpack:///./src/textile/re_ext.js","webpack:///./src/textile/list.js","webpack:///./src/textile/deflist.js","webpack:///./src/textile/table.js"],"names":[],"mappings":"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","file":"textile.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"textile\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"textile\"] = factory();\n\telse\n\t\troot[\"textile\"] = factory();\n})(this, function() {\nreturn \n\n\n/** WEBPACK FOOTER **\n ** webpack/universalModuleDefinition\n **/"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap 75feac9fe5b945b13943\n **/","/*\n** Textile parser for JavaScript\n**\n** Copyright (c) 2012 Borgar Þorsteinsson (MIT License).\n**\n*/\n\nconst merge = require( './merge' );\nconst { toHTML } = require( './jsonml' );\nconst { parseFlow } = require( './textile/flow' );\nconst { parseHtml } = require( './html' );\n\nfunction textile ( txt, opt ) {\n // get a throw-away copy of options\n opt = merge( merge({}, textile.defaults ), opt || {});\n // run the converter\n return parseFlow( txt, opt ).map( toHTML ).join( '' );\n};\nmodule.exports = textile;\n\n// options\ntextile.defaults = {\n // single-line linebreaks are converted to
    by default\n 'breaks': true\n};\ntextile.setOptions = textile.setoptions = function ( opt ) {\n merge( textile.defaults, opt );\n return this;\n};\n\ntextile.parse = textile.convert = textile;\ntextile.html_parser = parseHtml;\n\ntextile.jsonml = function ( txt, opt ) {\n // get a throw-away copy of options\n opt = merge( merge({}, textile.defaults ), opt || {});\n // parse and return tree\n return [ 'html' ].concat( parseFlow( txt, opt ) );\n};\ntextile.serialize = toHTML;\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/index.js\n **/","// merge object b properties into object a\nmodule.exports = function merge ( a, b ) {\n if ( b ) {\n for ( const k in b ) {\n a[ k ] = b[ k ];\n }\n }\n return a;\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/merge.js\n **/","/*\n** JSONML helper methods - http://www.jsonml.org/\n**\n** This provides the `JSONML` object, which contains helper\n** methods for rendering JSONML to HTML.\n**\n** Note that the tag ! is taken to mean comment, this is however\n** not specified in the JSONML spec.\n*/\n\nconst singletons = require( './html' ).singletons;\n\n// drop or add tab levels to JsonML tree\nfunction reIndent ( ml, shiftBy ) {\n // a bit obsessive, but there we are...\n if ( !shiftBy ) {\n return ml;\n }\n return ml.map( function ( s ) {\n if ( /^\\n\\t+/.test( s ) ) {\n if ( shiftBy < 0 ) {\n s = s.slice( 0, shiftBy );\n }\n else {\n for ( let i = 0; i < shiftBy; i++ ) {\n s += '\\t';\n }\n }\n }\n else if ( Array.isArray( s ) ) {\n return reIndent( s, shiftBy );\n }\n return s;\n });\n}\n\nfunction escape ( text, escapeQuotes ) {\n return text.replace( /&(?!(#\\d{2,}|#x[\\da-fA-F]{2,}|[a-zA-Z][a-zA-Z1-4]{1,6});)/g, '&' )\n .replace( //g, '>' )\n .replace( /\"/g, escapeQuotes ? '"' : '\"' )\n .replace( /'/g, escapeQuotes ? ''' : \"'\" );\n}\n\nfunction toHTML ( jsonml ) {\n jsonml = jsonml.concat();\n\n // basic case\n if ( typeof jsonml === 'string' ) {\n return escape( jsonml );\n }\n\n const tag = jsonml.shift();\n let attributes = {};\n let tagAttrs = '';\n const content = [];\n\n if ( jsonml.length && typeof jsonml[0] === 'object' && !Array.isArray( jsonml[0] ) ) {\n attributes = jsonml.shift();\n }\n\n while ( jsonml.length ) {\n content.push( toHTML( jsonml.shift() ) );\n }\n\n for ( const a in attributes ) {\n tagAttrs += ( attributes[a] == null )\n ? ` ${ a }`\n : ` ${ a }=\"${ escape( String( attributes[a] ), true ) }\"`;\n }\n\n // be careful about adding whitespace here for inline elements\n if ( tag === '!' ) {\n return ``;\n }\n else if ( tag in singletons ) {\n return `<${ tag }${ tagAttrs } />`;\n }\n else {\n return `<${ tag }${ tagAttrs }>${ content.join( '' ) }`;\n }\n}\n\nmodule.exports = {\n reIndent: reIndent,\n toHTML: toHTML,\n escape: escape\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/jsonml.js\n **/","const re = require( './re' );\nconst ribbon = require( './ribbon' );\n\nre.pattern.html_id = '[a-zA-Z][a-zA-Z\\\\d:]*';\nre.pattern.html_attr = '(?:\"[^\"]+\"|\\'[^\\']+\\'|[^>\\\\s]+)';\n\nconst reAttr = re.compile( /^\\s*([^=\\s]+)(?:\\s*=\\s*(\"[^\"]+\"|'[^']+'|[^>\\s]+))?/ );\nconst reComment = re.compile( /^/, 's' );\nconst reEndTag = re.compile( /^<\\/([:html_id:])([^>]*)>/ );\nconst reTag = re.compile( /^<([:html_id:])((?:\\s[^=\\s\\/]+(?:\\s*=\\s*[:html_attr:])?)+)?\\s*(\\/?)>(\\n*)/ );\nconst reHtmlTagBlock = re.compile( /^\\s*<([:html_id:](?::[a-zA-Z\\d]+)*)((?:\\s[^=\\s\\/]+(?:\\s*=\\s*[:html_attr:])?)+)?\\s*(\\/?)>(\\n*)/ );\n\n// area, base, basefont, bgsound, br, col, command, embed, frame, hr,\n// img, input, keygen, link, meta, param, source, track or wbr\nconst singletons = {\n br: 1,\n hr: 1,\n img: 1,\n link: 1,\n meta: 1,\n wbr: 1,\n area: 1,\n param: 1,\n input: 1,\n option: 1,\n base: 1,\n col: 1\n};\n\nfunction allowAll () {\n return true;\n}\n\nfunction testComment ( src ) {\n return reComment.exec( src );\n}\n\nfunction testOpenTagBlock ( src ) {\n return reHtmlTagBlock.exec( src );\n}\n\nfunction testOpenTag ( src ) {\n return reTag.exec( src );\n}\n\nfunction testCloseTag ( src ) {\n return reEndTag.exec( src );\n}\n\nfunction parseHtmlAttr ( attrSrc ) {\n // parse ATTR and add to element\n const attr = {};\n let m;\n while ( ( m = reAttr.exec( attrSrc ) ) ) {\n attr[ m[1] ] = ( typeof m[2] === 'string' ) ? m[2].replace( /^([\"'])(.*)\\1$/, '$2' ) : null;\n attrSrc = attrSrc.slice( m[0].length );\n }\n return attr;\n}\n\n// This \"indesciminately\" parses HTML text into a list of JSON-ML element\n// No steps are taken however to prevent things like

    - user can still create nonsensical but \"well-formed\" markup\nfunction parseHtml ( src, whitelistTags ) {\n const root = [];\n let list = root;\n const _stack = [];\n const oktag = whitelistTags ? function ( tag ) { return tag in whitelistTags; } : allowAll;\n let m;\n let tag;\n\n src = ( typeof src === 'string' ) ? ribbon( src ) : src;\n // loop\n do {\n // comment\n if ( ( m = testComment( src ) ) && oktag( '!' ) ) {\n src.advance( m[0] );\n list.push( [ '!', m[1] ] );\n }\n\n // end tag\n else if ( ( m = testCloseTag( src ) ) && oktag( m[1] ) ) {\n tag = m[1];\n if ( _stack.length ) {\n for ( let i = _stack.length - 1; i >= 0; i-- ) {\n const head = _stack[i];\n if ( head[0] === tag ) {\n _stack.splice( i );\n list = _stack[_stack.length - 1] || root;\n break;\n }\n }\n }\n src.advance( m[0] );\n }\n\n // open/void tag\n else if ( ( m = testOpenTag( src ) ) && oktag( m[1] ) ) {\n src.advance( m[0] );\n tag = m[1];\n const single = m[3] || m[1] in singletons;\n const tail = m[4];\n const element = [ tag ];\n\n // attributes\n if ( m[2] ) {\n element.push( parseHtmlAttr( m[2] ) );\n }\n\n // single tag\n if ( single ) {\n // let us add the element and continue our quest...\n list.push( element );\n if ( tail ) {\n list.push( tail );\n }\n }\n // open tag\n else {\n if ( tail ) {\n element.push( tail );\n }\n\n // TODO: some things auto close other things: ,
  • ,

    , \n // if ( tag === 'p' && _stack.length ) {\n // var seek = /^(p)$/;\n // for (var i=_stack.length-1; i>=0; i--) {\n // var head = _stack[i];\n // if ( seek.test( head[0] ) /* === tag */ ) {\n // //src.advance( m[0] );\n // _stack.splice( i );\n // list = _stack[i] || root;\n // }\n // }\n // }\n\n // TODO: some elements can move parser into \"text\" mode\n // style, xmp, iframe, noembed, noframe, textarea, title, script, noscript, plaintext\n // if ( /^(script)$/.test( tag ) ) { }\n\n _stack.push( element );\n list.push( element );\n list = element;\n }\n }\n // text content\n else {\n // no match, move by all \"uninteresting\" chars\n m = /([^<]+|[^\\0])/.exec( src );\n if ( m ) {\n list.push( m[0] );\n }\n src.advance( m ? m[0].length || 1 : 1 );\n }\n }\n while ( src.valueOf() );\n\n return root;\n}\n\nmodule.exports = {\n singletons: singletons,\n parseHtml: parseHtml,\n parseHtmlAttr: parseHtmlAttr,\n testCloseTag: testCloseTag,\n testOpenTagBlock: testOpenTagBlock,\n testOpenTag: testOpenTag,\n testComment: testComment\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/html.js\n **/","/*\n** Regular Expression helper methods\n**\n** This provides the `re` object, which contains several helper\n** methods for working with big regular expressions (soup).\n**\n*/\n\nconst _cache = {};\n\nconst re = module.exports = {\n\n pattern: {\n 'punct': '[!-/:-@\\\\[\\\\\\\\\\\\]-`{-~]',\n 'space': '\\\\s'\n },\n\n escape: function ( src ) {\n return src.replace( /[\\-\\[\\]\\{\\}\\(\\)\\*\\+\\?\\.,\\\\\\^\\$\\|#\\s]/g, '\\\\$&' );\n },\n\n collapse: function ( src ) {\n return src.replace( /(?:#.*?(?:\\n|$))/g, '' )\n .replace( /\\s+/g, '' );\n },\n\n expandPatterns: function ( src ) {\n // TODO: provide escape for patterns: \\[:pattern:] ?\n return src.replace( /\\[:\\s*(\\w+)\\s*:\\]/g, function ( m, k ) {\n const ex = re.pattern[k];\n if ( ex ) {\n return re.expandPatterns( ex );\n }\n else {\n throw new Error( 'Pattern ' + m + ' not found in ' + src );\n }\n });\n },\n\n isRegExp: function ( r ) {\n return Object.prototype.toString.call( r ) === '[object RegExp]';\n },\n\n compile: function ( src, flags ) {\n if ( re.isRegExp( src ) ) {\n if ( arguments.length === 1 ) { // no flags arg provided, use the RegExp one\n flags = ( src.global ? 'g' : '' ) +\n ( src.ignoreCase ? 'i' : '' ) +\n ( src.multiline ? 'm' : '' );\n }\n src = src.source;\n }\n // don't do the same thing twice\n const ckey = src + ( flags || '' );\n if ( ckey in _cache ) {\n return _cache[ ckey ];\n }\n // allow classes\n let rx = re.expandPatterns( src );\n // allow verbose expressions\n if ( flags && /x/.test( flags ) ) {\n rx = re.collapse( rx );\n }\n // allow dotall expressions\n if ( flags && /s/.test( flags ) ) {\n rx = rx.replace( /([^\\\\])\\./g, '$1[^\\\\0]' );\n }\n // TODO: test if MSIE and add replace \\s with [\\s\\u00a0] if it is?\n // clean flags and output new regexp\n flags = ( flags || '' ).replace( /[^gim]/g, '' );\n return ( _cache[ ckey ] = new RegExp( rx, flags ) );\n }\n\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/re.js\n **/","module.exports = function ribbon ( feed ) {\n const org = String( feed );\n let slot = null;\n let pos = 0;\n\n return {\n\n save: function () {\n slot = pos;\n },\n\n load: function () {\n pos = slot;\n feed = org.slice( pos );\n this.$ = feed;\n },\n\n advance: function ( n ) {\n pos += ( typeof n === 'string' ) ? n.length : n;\n feed = org.slice( pos );\n this.$ = feed;\n return feed;\n },\n\n lookbehind: function ( nchars ) {\n nchars = nchars == null ? 1 : nchars;\n return org.slice( pos - nchars, pos );\n },\n\n startsWith: function ( s ) {\n return feed.substring( 0, s.length ) === s;\n },\n\n valueOf: function () {\n this.$ = feed;\n return feed;\n },\n\n toString: function () {\n this.$ = feed;\n return feed;\n }\n\n };\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/ribbon.js\n **/","/*\n** textile flow content parser\n*/\nconst builder = require( '../builder' );\nconst ribbon = require( '../ribbon' );\nconst re = require( '../re' );\nconst fixLinks = require( '../fixlinks' );\n\nconst { parseHtml, parseHtmlAttr, singletons, testComment, testOpenTagBlock } = require( '../html' );\n\nconst { parsePhrase } = require( './phrase' );\nconst { copyAttr, parseAttr } = require( './attr' );\nconst { testList, parseList } = require( './list' );\nconst { testDefList, parseDefList } = require( './deflist' );\nconst { testTable, parseTable } = require( './table' );\n\nconst { txblocks, txlisthd, txattr } = require( './re_ext' );\nre.pattern.txblocks = txblocks;\nre.pattern.txlisthd = txlisthd;\nre.pattern.txattr = txattr;\n\n// HTML tags allowed in the document (root) level that trigger HTML parsing\nconst allowedBlocktags = {\n 'p': 0,\n 'hr': 0,\n 'ul': 1,\n 'ol': 0,\n 'li': 0,\n 'div': 1,\n 'pre': 0,\n 'object': 1,\n 'script': 0,\n 'noscript': 0,\n 'blockquote': 1,\n 'notextile': 1\n};\n\nconst reBlock = re.compile( /^([:txblocks:])/ );\n// const reBlockSE = re.compile( /^[:txblocks:]$/ );\nconst reBlockNormal = re.compile( /^(.*?)($|\\r?\\n(?=[:txlisthd:])|\\r?\\n(?:\\s*\\n|$)+)/, 's' );\nconst reBlockExtended = re.compile( /^(.*?)($|\\r?\\n(?=[:txlisthd:])|\\r?\\n+(?=[:txblocks:][:txattr:]\\.))/, 's' );\nconst reRuler = /^(\\-\\-\\-+|\\*\\*\\*+|___+)(\\r?\\n\\s+|$)/;\nconst reLinkRef = re.compile( /^\\[([^\\]]+)\\]((?:https?:\\/\\/|\\/)\\S+)(?:\\s*\\n|$)/ );\nconst reFootnoteDef = /^fn\\d+$/;\n\nfunction paragraph ( s, tag, pba, linebreak, options ) {\n tag = tag || 'p';\n let out = [];\n s.split( /(?:\\r?\\n){2,}/ ).forEach( function ( bit, i ) {\n if ( tag === 'p' && /^\\s/.test( bit ) ) {\n // no-paragraphs\n // WTF?: Why does Textile not allow linebreaks in spaced lines\n bit = bit.replace( /\\r?\\n[\\t ]/g, ' ' ).trim();\n out = out.concat( parsePhrase( bit, options ) );\n }\n else {\n if ( linebreak && i ) { out.push( linebreak ); }\n out.push( pba ? [ tag, pba ].concat( parsePhrase( bit, options ) )\n : [ tag ].concat( parsePhrase( bit, options ) ) );\n }\n });\n return out;\n};\n\nfunction parseFlow ( src, options ) {\n const list = builder();\n\n let linkRefs;\n let m;\n\n src = ribbon( src.replace( /^( *\\r?\\n)+/, '' ) );\n\n // loop\n while ( src.valueOf() ) {\n src.save();\n\n // link_ref -- this goes first because it shouldn't trigger a linebreak\n if ( ( m = reLinkRef.exec( src ) ) ) {\n if ( !linkRefs ) { linkRefs = {}; }\n src.advance( m[0] );\n linkRefs[m[1]] = m[2];\n continue;\n }\n\n // add linebreak\n list.linebreak();\n\n // named block\n if ( ( m = reBlock.exec( src ) ) ) {\n src.advance( m[0] );\n const blockType = m[0];\n let pba = parseAttr( src, blockType );\n\n if ( pba ) {\n src.advance( pba[0] );\n pba = pba[1];\n }\n if ( ( m = /^\\.(\\.?)(?:\\s|(?=:))/.exec( src ) ) ) {\n // FIXME: this whole copyAttr seems rather strange?\n // slurp rest of block\n const extended = !!m[1];\n const reBlockGlob = ( extended ? reBlockExtended : reBlockNormal );\n m = reBlockGlob.exec( src.advance( m[0] ) );\n src.advance( m[0] );\n // bq | bc | notextile | pre | h# | fn# | p | ###\n if ( blockType === 'bq' ) {\n let inner = m[1];\n if ( ( m = /^:(\\S+)\\s+/.exec( inner ) ) ) {\n if ( !pba ) { pba = {}; }\n pba.cite = m[1];\n inner = inner.slice( m[0].length );\n }\n // RedCloth adds all attr to both: this is bad because it produces duplicate IDs\n const par = paragraph( inner, 'p', copyAttr( pba, { 'cite': 1, 'id': 1 }), '\\n', options );\n list.add( [ 'blockquote', pba, '\\n' ].concat( par ).concat( [ '\\n' ] ) );\n // FIXME: looks like .linebreak can work here\n }\n else if ( blockType === 'bc' ) {\n const subPba = ( pba ) ? copyAttr( pba, { 'id': 1 }) : null;\n list.add( [ 'pre', pba, ( subPba ? [ 'code', subPba, m[1] ] : [ 'code', m[1] ] ) ] );\n }\n else if ( blockType === 'notextile' ) {\n list.merge( parseHtml( m[1] ) );\n }\n else if ( blockType === '###' ) {\n // ignore the insides\n }\n else if ( blockType === 'pre' ) {\n // I disagree with RedCloth, but agree with PHP here:\n // \"pre(foo#bar).. line1\\n\\nline2\" prevents multiline preformat blocks\n // ...which seems like the whole point of having an extended pre block?\n list.add( [ 'pre', pba, m[1] ] );\n }\n else if ( reFootnoteDef.test( blockType ) ) { // footnote\n // Need to be careful: RedCloth fails \"fn1(foo#m). footnote\" -- it confuses the ID\n const fnid = blockType.replace( /\\D+/g, '' );\n if ( !pba ) { pba = {}; }\n pba.class = ( pba['class'] ? pba['class'] + ' ' : '' ) + 'footnote';\n pba.id = 'fn' + fnid;\n list.add( [ 'p', pba, [ 'a', { 'href': '#fnr' + fnid }, [ 'sup', fnid ] ], ' ' ]\n .concat( parsePhrase( m[1], options ) ) );\n }\n else { // heading | paragraph\n list.merge( paragraph( m[1], blockType, pba, '\\n', options ) );\n }\n continue;\n }\n else {\n src.load();\n }\n }\n\n // HTML comment\n if ( ( m = testComment( src ) ) ) {\n src.advance( m[0] + ( /(?:\\s*\\n+)+/.exec( src ) || [] )[0] );\n list.add( [ '!', m[1] ] );\n continue;\n }\n\n // block HTML\n if ( ( m = testOpenTagBlock( src ) ) ) {\n const tag = m[1];\n const single = m[3] || tag in singletons;\n const tail = m[4];\n\n // Unsurprisingly, all Textile implementations I have tested have trouble parsing simple HTML:\n //\n // \"
    a\\n
    b\\n
    c\\n
    d\"\n //\n // I simply match them here as there is no way anyone is using nested HTML today, or if they\n // are, then this will at least output less broken HTML as redundant tags will get quoted.\n\n // Is block tag? ...\n if ( tag in allowedBlocktags ) {\n src.advance( m[0] );\n\n let element = [ tag ];\n\n if ( m[2] ) {\n element.push( parseHtmlAttr( m[2] ) );\n }\n\n // single tag\n if ( single ) {\n // let us add the element and continue our quest...\n list.add( element );\n continue;\n }\n // block\n else {\n // gulp up the rest of this block...\n const reEndTag = re.compile( `^(.*?)(\\\\s*)()(\\\\s*)`, 's' );\n if ( ( m = reEndTag.exec( src ) ) ) {\n src.advance( m[0] );\n if ( tag === 'pre' ) {\n element.push( tail );\n element = element.concat( parseHtml( m[1].replace( /(\\r?\\n)+$/, '' ), { 'code': 1 }) );\n if ( m[2] ) { element.push( m[2] ); }\n list.add( element );\n }\n else if ( tag === 'notextile' ) {\n element = parseHtml( m[1].trim() );\n list.merge( element );\n }\n else if ( tag === 'script' || tag === 'noscript' ) {\n element.push( tail + m[1] );\n list.add( element );\n }\n else {\n // These strange (and unnecessary) linebreak tests are here to get the\n // tests working perfectly. In reality, this doesn't matter one bit.\n if ( /\\n/.test( tail ) ) { element.push( '\\n' ); }\n if ( /\\n/.test( m[1] ) ) {\n element = element.concat( parseFlow( m[1], options ) );\n }\n else {\n element = element.concat( parsePhrase( m[1].replace( /^ +/, '' ), options ) );\n }\n if ( /\\n/.test( m[2] ) ) { element.push( '\\n' ); }\n\n list.add( element );\n }\n continue;\n }\n }\n }\n src.load();\n }\n\n // ruler\n if ( ( m = reRuler.exec( src ) ) ) {\n src.advance( m[0] );\n list.add( [ 'hr' ] );\n continue;\n }\n\n // list\n if ( ( m = testList( src ) ) ) {\n src.advance( m[0] );\n list.add( parseList( m[0], options ) );\n continue;\n }\n\n // definition list\n if ( ( m = testDefList( src ) ) ) {\n src.advance( m[0] );\n list.add( parseDefList( m[0], options ) );\n continue;\n }\n\n // table\n if ( ( m = testTable( src ) ) ) {\n src.advance( m[0] );\n list.add( parseTable( m[1], options ) );\n continue;\n }\n\n // paragraph\n m = reBlockNormal.exec( src );\n list.merge( paragraph( m[1], 'p', undefined, '\\n', options ) );\n src.advance( m[0] );\n }\n\n return linkRefs ? fixLinks( list.get(), linkRefs ) : list.get();\n}\n\nexports.parseFlow = parseFlow;\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/flow.js\n **/","module.exports = function builder ( initArr ) {\n const arr = Array.isArray( initArr ) ? initArr : [];\n\n return {\n add: function ( node ) {\n if ( typeof node === 'string' &&\n typeof arr[ arr.length - 1 ] === 'string' ) {\n // join if possible\n arr[ arr.length - 1 ] += node;\n }\n else if ( Array.isArray( node ) ) {\n arr.push( node.filter( s => s !== undefined ) );\n }\n else if ( node ) {\n arr.push( node );\n }\n return this;\n },\n\n merge: function ( arr ) {\n for ( let i = 0, l = arr.length; i < l; i++ ) {\n this.add( arr[i] );\n }\n return this;\n },\n\n linebreak: function () {\n if ( arr.length ) {\n this.add( '\\n' );\n }\n },\n\n get: function () {\n return arr;\n }\n };\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/builder.js\n **/","// recurse the tree and swap out any \"href\" attributes\n// this uses the context as the replace dictionary so it can be fed to Array#map\nmodule.exports = function fixLinks ( ml, dict ) {\n if ( Array.isArray( ml ) ) {\n if ( ml[0] === 'a' ) { // found a link\n const attr = ml[1];\n if ( typeof attr === 'object' && 'href' in attr && attr.href in dict ) {\n attr.href = dict[attr.href];\n }\n }\n for ( let i = 0, l = ml.length; i < l; i++ ) {\n if ( Array.isArray( ml[i] ) ) {\n fixLinks( ml[i], dict );\n }\n }\n }\n return ml;\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/fixlinks.js\n **/","/* textile inline parser */\n\nconst ribbon = require( '../ribbon' );\nconst builder = require( '../builder' );\nconst re = require( '../re' );\n\nconst { parseAttr } = require( './attr' );\nconst { parseGlyph } = require( './glyph' );\nconst { parseHtmlAttr, singletons, testComment, testOpenTag } = require( '../html' );\n\nconst { ucaps, txattr, txcite } = require( './re_ext' );\nre.pattern.txattr = txattr;\nre.pattern.txcite = txcite;\nre.pattern.ucaps = ucaps;\n\nconst phraseConvert = {\n '*': 'strong',\n '**': 'b',\n '??': 'cite',\n '_': 'em',\n '__': 'i',\n '-': 'del',\n '%': 'span',\n '+': 'ins',\n '~': 'sub',\n '^': 'sup',\n '@': 'code'\n};\n\nconst rePhrase = /^([\\[\\{]?)(__?|\\*\\*?|\\?\\?|[\\-\\+\\^~@%])/;\nconst reImage = re.compile( /^!(?!\\s)([:txattr:](?:\\.[^\\n\\S]|\\.(?:[^\\.\\/]))?)([^!\\s]+?) ?(?:\\(((?:[^\\(\\)]+|\\([^\\(\\)]+\\))+)\\))?!(?::([^\\s]+?(?=[!-\\.:-@\\[\\\\\\]-`{-~](?:$|\\s)|\\s|$)))?/ );\nconst reImageFenced = re.compile( /^\\[!(?!\\s)([:txattr:](?:\\.[^\\n\\S]|\\.(?:[^\\.\\/]))?)([^!\\s]+?) ?(?:\\(((?:[^\\(\\)]+|\\([^\\(\\)]+\\))+)\\))?!(?::([^\\s]+?(?=[!-\\.:-@\\[\\\\\\]-`{-~](?:$|\\s)|\\s|$)))?\\]/ );\n// NB: there is an exception in here to prevent matching \"TM)\"\nconst reCaps = re.compile( /^((?!TM\\)|tm\\))[[:ucaps:]](?:[[:ucaps:]\\d]{1,}(?=\\()|[[:ucaps:]\\d]{2,}))(?:\\((.*?)\\))?(?=\\W|$)/ );\nconst reLink = re.compile( /^\"(?!\\s)((?:[^\\n\"]|\"(?![\\s:])[^\\n\"]+\"(?!:))+)\"[:txcite:]/ );\nconst reLinkFenced = /^\\[\"([^\\n]+?)\":((?:\\[[a-z0-9]*\\]|[^\\]])+)\\]/;\nconst reLinkTitle = /\\s*\\(((?:\\([^\\(\\)]*\\)|[^\\(\\)])+)\\)$/;\nconst reFootnote = /^\\[(\\d+)(!?)\\]/;\n\nfunction parsePhrase ( src, options ) {\n src = ribbon( src );\n\n const list = builder();\n let m;\n let pba;\n\n // loop\n do {\n src.save();\n\n // linebreak -- having this first keeps it from messing to much with other phrases\n if ( src.startsWith( '\\r\\n' ) ) {\n src.advance( 1 ); // skip cartridge returns\n }\n if ( src.startsWith( '\\n' ) ) {\n src.advance( 1 );\n if ( options.breaks ) {\n list.add( [ 'br' ] );\n }\n list.add( '\\n' );\n continue;\n }\n\n // inline notextile\n if ( ( m = /^==(.*?)==/.exec( src ) ) ) {\n src.advance( m[0] );\n list.add( m[1] );\n continue;\n }\n\n // lookbehind => /([\\s>.,\"'?!;:])$/\n const behind = src.lookbehind( 1 );\n const boundary = !behind || /^[\\s>.,\"'?!;:()]$/.test( behind );\n // FIXME: need to test right boundary for phrases as well\n if ( ( m = rePhrase.exec( src ) ) && ( boundary || m[1] ) ) {\n src.advance( m[0] );\n const tok = m[2];\n const fence = m[1];\n const phraseType = phraseConvert[tok];\n const code = phraseType === 'code';\n\n if ( ( pba = !code && parseAttr( src, phraseType, tok ) ) ) {\n src.advance( pba[0] );\n pba = pba[1];\n }\n // FIXME: if we can't match the fence on the end, we should output fence-prefix as normal text\n // seek end\n let mMid;\n let mEnd;\n if ( fence === '[' ) {\n mMid = '^(.*?)';\n mEnd = '(?:])';\n }\n else if ( fence === '{' ) {\n mMid = '^(.*?)';\n mEnd = '(?:})';\n }\n else {\n const t1 = re.escape( tok.charAt( 0 ) );\n mMid = ( code ) ? '^(\\\\S+|\\\\S+.*?\\\\S)'\n : `^([^\\\\s${ t1 }]+|[^\\\\s${ t1 }].*?\\\\S(${ t1 }*))`;\n mEnd = '(?=$|[\\\\s.,\"\\'!?;:()«»„“”‚‘’])';\n }\n const rx = re.compile( `${ mMid }(${ re.escape( tok ) })${ mEnd }` );\n if ( ( m = rx.exec( src ) ) && m[1] ) {\n src.advance( m[0] );\n if ( code ) {\n list.add( [ phraseType, m[1] ] );\n }\n else {\n list.add( [ phraseType, pba ].concat( parsePhrase( m[1], options ) ) );\n }\n continue;\n }\n // else\n src.load();\n }\n\n // image\n if ( ( m = reImage.exec( src ) ) || ( m = reImageFenced.exec( src ) ) ) {\n src.advance( m[0] );\n\n pba = m[1] && parseAttr( m[1], 'img' );\n const attr = pba ? pba[1] : { 'src': '' };\n let img = [ 'img', attr ];\n attr.src = m[2];\n attr.alt = m[3] ? ( attr.title = m[3] ) : '';\n\n if ( m[4] ) { // +cite causes image to be wraped with a link (or link_ref)?\n // TODO: support link_ref for image cite\n img = [ 'a', { 'href': m[4] }, img ];\n }\n list.add( img );\n continue;\n }\n\n // html comment\n if ( ( m = testComment( src ) ) ) {\n src.advance( m[0] );\n list.add( [ '!', m[1] ] );\n continue;\n }\n // html tag\n // TODO: this seems to have a lot of overlap with block tags... DRY?\n if ( ( m = testOpenTag( src ) ) ) {\n src.advance( m[0] );\n const tag = m[1];\n const single = m[3] || m[1] in singletons;\n let element = [ tag ];\n const tail = m[4];\n if ( m[2] ) {\n element.push( parseHtmlAttr( m[2] ) );\n }\n if ( single ) { // single tag\n list.add( element ).add( tail );\n continue;\n }\n else { // need terminator\n // gulp up the rest of this block...\n const reEndTag = re.compile( `^(.*?)()`, 's' );\n if ( ( m = reEndTag.exec( src ) ) ) {\n src.advance( m[0] );\n if ( tag === 'code' ) {\n element.push( tail, m[1] );\n }\n else if ( tag === 'notextile' ) {\n list.merge( parsePhrase( m[1], options ) );\n continue;\n }\n else {\n element = element.concat( parsePhrase( m[1], options ) );\n }\n list.add( element );\n continue;\n }\n // end tag is missing, treat tag as normal text...\n }\n src.load();\n }\n\n // footnote\n if ( ( m = reFootnote.exec( src ) ) && /\\S/.test( behind ) ) {\n src.advance( m[0] );\n list.add( [ 'sup', { 'class': 'footnote', 'id': 'fnr' + m[1] },\n ( m[2] === '!' ? m[1] // \"!\" suppresses the link\n : [ 'a', { href: '#fn' + m[1] }, m[1] ] )\n ] );\n continue;\n }\n\n // caps / abbr\n if ( ( m = reCaps.exec( src ) ) ) {\n src.advance( m[0] );\n let caps = [ 'span', { 'class': 'caps' }, m[1] ];\n if ( m[2] ) {\n // FIXME: use , not acronym!\n caps = [ 'acronym', { 'title': m[2] }, caps ];\n }\n list.add( caps );\n continue;\n }\n\n // links\n if ( ( boundary && ( m = reLink.exec( src ) ) ) ||\n ( m = reLinkFenced.exec( src ) ) ) {\n src.advance( m[0] );\n let title = m[1].match( reLinkTitle );\n let inner = ( title ) ? m[1].slice( 0, m[1].length - title[0].length ) : m[1];\n if ( ( pba = parseAttr( inner, 'a' ) ) ) {\n inner = inner.slice( pba[0] );\n pba = pba[1];\n }\n else {\n pba = {};\n }\n if ( title && !inner ) {\n inner = title[0];\n title = '';\n }\n pba.href = m[2];\n if ( title ) { pba.title = title[1]; }\n list.add( [ 'a', pba ].concat( parsePhrase( inner.replace( /^(\\.?\\s*)/, '' ), options ) ) );\n continue;\n }\n\n // no match, move by all \"uninteresting\" chars\n m = /([a-zA-Z0-9,.':]+|[ \\f\\r\\t\\v\\xA0\\u2028\\u2029]+|[^\\0])/.exec( src );\n if ( m ) {\n list.add( m[0] );\n }\n src.advance( m ? m[0].length || 1 : 1 );\n }\n while ( src.valueOf() );\n\n return list.get().map( parseGlyph );\n}\n\nexports.parsePhrase = parsePhrase;\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/phrase.js\n **/","const reClassid = /^\\(([^\\(\\)\\n]+)\\)/;\nconst rePaddingL = /^(\\(+)/;\nconst rePaddingR = /^(\\)+)/;\nconst reAlignBlock = /^(<>|<|>|=)/;\nconst reAlignImg = /^(<|>|=)/;\nconst reVAlign = /^(~|\\^|\\-)/;\nconst reColSpan = /^\\\\(\\d+)/;\nconst reRowSpan = /^\\/(\\d+)/;\nconst reStyles = /^\\{([^\\}]*)\\}/;\nconst reCSS = /^\\s*([^:\\s]+)\\s*:\\s*(.+)\\s*$/;\nconst reLang = /^\\[([^\\[\\]\\n]+)\\]/;\n\nconst pbaAlignLookup = {\n '<': 'left',\n '=': 'center',\n '>': 'right',\n '<>': 'justify'\n};\n\nconst pbaVAlignLookup = {\n '~': 'bottom',\n '^': 'top',\n '-': 'middle'\n};\n\nfunction copyAttr ( s, blacklist ) {\n if ( !s ) { return undefined; }\n const d = {};\n for ( const k in s ) {\n if ( k in s && ( !blacklist || !( k in blacklist ) ) ) {\n d[ k ] = s[ k ];\n }\n }\n return d;\n}\n\nfunction testBlock ( name ) {\n // \"in\" test would be better but what about fn#.?\n return /^(?:table|t[dh]|t(?:foot|head|body)|b[qc]|div|notextile|pre|h[1-6]|fn\\\\d+|p|###)$/.test( name );\n}\n\n/*\n The attr bit causes massive problems for span elements when parentheses are used.\n Parentheses are a total mess and, unsurprisingly, cause trip-ups:\n\n RC: `_{display:block}(span) span (span)_` -> `(span) span (span)`\n PHP: `_{display:block}(span) span (span)_` -> `(span) span (span)`\n\n PHP and RC seem to mostly solve this by not parsing a final attr parens on spans if the\n following character is a non-space. I've duplicated that: Class/ID is not matched on spans\n if it is followed by `endToken` or .\n\n Lang is not matched here if it is followed by the end token. Theoretically I could limit the lang\n attribute to /^\\[[a-z]{2+}(\\-[a-zA-Z0-9]+)*\\]/ because Textile is layered on top of HTML which\n only accepts valid BCP 47 language tags, but who knows what atrocities are being preformed\n out there in the real world. So this attempts to emulate the other libraries.\n*/\nfunction parseAttr ( input, element, endToken ) {\n input = String( input );\n if ( !input || element === 'notextile' ) {\n return undefined;\n }\n\n let m;\n const st = {};\n const o = { 'style': st };\n let remaining = input;\n\n const isBlock = testBlock( element );\n const isImg = element === 'img';\n const isList = element === 'li';\n const isPhrase = !isBlock && !isImg && element !== 'a';\n const reAlign = ( isImg ) ? reAlignImg : reAlignBlock;\n\n do {\n if ( ( m = reStyles.exec( remaining ) ) ) {\n m[1].split( ';' ).forEach( function ( p ) {\n const d = p.match( reCSS );\n if ( d ) { st[ d[1] ] = d[2]; }\n });\n remaining = remaining.slice( m[0].length );\n continue;\n }\n\n if ( ( m = reLang.exec( remaining ) ) ) {\n const rm = remaining.slice( m[0].length );\n if ( ( !rm && isPhrase ) ||\n ( endToken && endToken === rm.slice( 0, endToken.length ) ) ) {\n m = null;\n }\n else {\n o['lang'] = m[1];\n remaining = remaining.slice( m[0].length );\n }\n continue;\n }\n\n if ( ( m = reClassid.exec( remaining ) ) ) {\n const rm = remaining.slice( m[0].length );\n if (\n ( !rm && isPhrase ) ||\n ( endToken && ( rm[0] === ' ' || endToken === rm.slice( 0, endToken.length ) ) )\n ) {\n m = null;\n }\n else {\n const bits = m[1].split( '#' );\n if ( bits[0] ) { o.class = bits[0]; }\n if ( bits[1] ) { o.id = bits[1]; }\n remaining = rm;\n }\n continue;\n }\n\n if ( isBlock || isList ) {\n if ( ( m = rePaddingL.exec( remaining ) ) ) {\n st[ 'padding-left' ] = `${ m[1].length }em`;\n remaining = remaining.slice( m[0].length );\n continue;\n }\n if ( ( m = rePaddingR.exec( remaining ) ) ) {\n st[ 'padding-right' ] = `${ m[1].length }em`;\n remaining = remaining.slice( m[0].length );\n continue;\n }\n }\n\n // only for blocks:\n if ( isImg || isBlock || isList ) {\n if ( ( m = reAlign.exec( remaining ) ) ) {\n const align = pbaAlignLookup[ m[1] ];\n if ( isImg ) {\n o[ 'align' ] = align;\n }\n else {\n st[ 'text-align' ] = align;\n }\n remaining = remaining.slice( m[0].length );\n continue;\n }\n }\n\n // only for table cells\n if ( element === 'td' || element === 'tr' ) {\n if ( ( m = reVAlign.exec( remaining ) ) ) {\n st[ 'vertical-align' ] = pbaVAlignLookup[ m[1] ];\n remaining = remaining.slice( m[0].length );\n continue;\n }\n }\n if ( element === 'td' ) {\n if ( ( m = reColSpan.exec( remaining ) ) ) {\n o[ 'colspan' ] = m[1];\n remaining = remaining.slice( m[0].length );\n continue;\n }\n if ( ( m = reRowSpan.exec( remaining ) ) ) {\n o[ 'rowspan' ] = m[1];\n remaining = remaining.slice( m[0].length );\n continue;\n }\n }\n }\n while ( m );\n\n // collapse styles\n const s = [];\n for ( const v in st ) {\n s.push( `${ v }:${ st[v] }` );\n }\n if ( s.length ) {\n o.style = s.join( ';' );\n }\n else {\n delete o.style;\n }\n\n return ( remaining === input ) ? undefined : [ input.length - remaining.length, o ];\n}\n\nmodule.exports = {\n copyAttr: copyAttr,\n parseAttr: parseAttr\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/attr.js\n **/","/* textile glyph parser */\n\nconst re = require( '../re' );\n\nconst reApostrophe = /(\\w)'(\\w)/g;\nconst reArrow = /([^\\-]|^)->/;\nconst reClosingDQuote = re.compile( /([^\\s\\[\\(])\"(?=$|\\s|[:punct:])/g );\nconst reClosingSQuote = re.compile( /([^\\s\\[\\(])'(?=$|\\s|[:punct:])/g );\nconst reCopyright = /(\\b ?|\\s|^)(?:\\(C\\)|\\[C\\])/gi;\nconst reDimsign = /([\\d\\.,]+['\"]? ?)x( ?)(?=[\\d\\.,]['\"]?)/g;\nconst reDoublePrime = re.compile( /(\\d*[\\.,]?\\d+)\"(?=\\s|$|[:punct:])/g );\nconst reEllipsis = /([^.]?)\\.{3}/g;\nconst reEmdash = /(^|[\\s\\w])--([\\s\\w]|$)/g;\nconst reEndash = / - /g;\nconst reOpenDQuote = /\"/g;\nconst reOpenSQuote = /'/g;\nconst reRegistered = /(\\b ?|\\s|^)(?:\\(R\\)|\\[R\\])/gi;\nconst reSinglePrime = re.compile( /(\\d*[\\.,]?\\d+)'(?=\\s|$|[:punct:])/g );\nconst reTrademark = /(\\b ?|\\s|^)(?:\\((?:TM|tm)\\)|\\[(?:TM|tm)\\])/g;\n\nexports.parseGlyph = function parseGlyph ( src ) {\n if ( typeof src !== 'string' ) {\n return src;\n }\n // NB: order is important here ...\n return src\n .replace( reArrow, '$1→' )\n .replace( reDimsign, '$1×$2' )\n .replace( reEllipsis, '$1…' )\n .replace( reEmdash, '$1—$2' )\n .replace( reEndash, ' – ' )\n .replace( reTrademark, '$1™' )\n .replace( reRegistered, '$1®' )\n .replace( reCopyright, '$1©' )\n // double quotes\n .replace( reDoublePrime, '$1″' )\n .replace( reClosingDQuote, '$1”' )\n .replace( reOpenDQuote, '“' )\n // single quotes\n .replace( reSinglePrime, '$1′' )\n .replace( reApostrophe, '$1’$2' )\n .replace( reClosingSQuote, '$1’' )\n .replace( reOpenSQuote, '‘' )\n // fractions and degrees\n .replace( /[\\(\\[]1\\/4[\\]\\)]/, '¼' )\n .replace( /[\\(\\[]1\\/2[\\]\\)]/, '½' )\n .replace( /[\\(\\[]3\\/4[\\]\\)]/, '¾' )\n .replace( /[\\(\\[]o[\\]\\)]/, '°' )\n .replace( /[\\(\\[]\\+\\/\\-[\\]\\)]/, '±' );\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/glyph.js\n **/","/* eslint camelcase: 0 */\n\nexports.txblocks = '(?:b[qc]|div|notextile|pre|h[1-6]|fn\\\\d+|p|###)';\n\nexports.ucaps = 'A-Z' +\n // Latin extended À-Þ\n '\\u00c0-\\u00d6\\u00d8-\\u00de' +\n // Latin caps with embelishments and ligatures...\n '\\u0100\\u0102\\u0104\\u0106\\u0108\\u010a\\u010c\\u010e\\u0110\\u0112\\u0114\\u0116\\u0118\\u011a\\u011c\\u011e\\u0120\\u0122\\u0124\\u0126\\u0128\\u012a\\u012c\\u012e\\u0130\\u0132\\u0134\\u0136\\u0139\\u013b\\u013d\\u013f' +\n '\\u0141\\u0143\\u0145\\u0147\\u014a\\u014c\\u014e\\u0150\\u0152\\u0154\\u0156\\u0158\\u015a\\u015c\\u015e\\u0160\\u0162\\u0164\\u0166\\u0168\\u016a\\u016c\\u016e\\u0170\\u0172\\u0174\\u0176\\u0178\\u0179\\u017b\\u017d' +\n '\\u0181\\u0182\\u0184\\u0186\\u0187\\u0189-\\u018b\\u018e-\\u0191\\u0193\\u0194\\u0196-\\u0198\\u019c\\u019d\\u019f\\u01a0\\u01a2\\u01a4\\u01a6\\u01a7\\u01a9\\u01ac\\u01ae\\u01af\\u01b1-\\u01b3\\u01b5\\u01b7\\u01b8\\u01bc' +\n '\\u01c4\\u01c7\\u01ca\\u01cd\\u01cf\\u01d1\\u01d3\\u01d5\\u01d7\\u01d9\\u01db\\u01de\\u01e0\\u01e2\\u01e4\\u01e6\\u01e8\\u01ea\\u01ec\\u01ee\\u01f1\\u01f4\\u01f6-\\u01f8\\u01fa\\u01fc\\u01fe' +\n '\\u0200\\u0202\\u0204\\u0206\\u0208\\u020a\\u020c\\u020e\\u0210\\u0212\\u0214\\u0216\\u0218\\u021a\\u021c\\u021e\\u0220\\u0222\\u0224\\u0226\\u0228\\u022a\\u022c\\u022e\\u0230\\u0232\\u023a\\u023b\\u023d\\u023e' +\n '\\u0241\\u0243-\\u0246\\u0248\\u024a\\u024c\\u024e' +\n '\\u1e00\\u1e02\\u1e04\\u1e06\\u1e08\\u1e0a\\u1e0c\\u1e0e\\u1e10\\u1e12\\u1e14\\u1e16\\u1e18\\u1e1a\\u1e1c\\u1e1e\\u1e20\\u1e22\\u1e24\\u1e26\\u1e28\\u1e2a\\u1e2c\\u1e2e\\u1e30\\u1e32\\u1e34\\u1e36\\u1e38\\u1e3a\\u1e3c\\u1e3e\\u1e40' +\n '\\u1e42\\u1e44\\u1e46\\u1e48\\u1e4a\\u1e4c\\u1e4e\\u1e50\\u1e52\\u1e54\\u1e56\\u1e58\\u1e5a\\u1e5c\\u1e5e\\u1e60\\u1e62\\u1e64\\u1e66\\u1e68\\u1e6a\\u1e6c\\u1e6e\\u1e70\\u1e72\\u1e74\\u1e76\\u1e78\\u1e7a\\u1e7c\\u1e7e' +\n '\\u1e80\\u1e82\\u1e84\\u1e86\\u1e88\\u1e8a\\u1e8c\\u1e8e\\u1e90\\u1e92\\u1e94\\u1e9e\\u1ea0\\u1ea2\\u1ea4\\u1ea6\\u1ea8\\u1eaa\\u1eac\\u1eae\\u1eb0\\u1eb2\\u1eb4\\u1eb6\\u1eb8\\u1eba\\u1ebc\\u1ebe' +\n '\\u1ec0\\u1ec2\\u1ec4\\u1ec6\\u1ec8\\u1eca\\u1ecc\\u1ece\\u1ed0\\u1ed2\\u1ed4\\u1ed6\\u1ed8\\u1eda\\u1edc\\u1ede\\u1ee0\\u1ee2\\u1ee4\\u1ee6\\u1ee8\\u1eea\\u1eec\\u1eee\\u1ef0\\u1ef2\\u1ef4\\u1ef6\\u1ef8\\u1efa\\u1efc\\u1efe' +\n '\\u2c60\\u2c62-\\u2c64\\u2c67\\u2c69\\u2c6b\\u2c6d-\\u2c70\\u2c72\\u2c75\\u2c7e\\u2c7f' +\n '\\ua722\\ua724\\ua726\\ua728\\ua72a\\ua72c\\ua72e\\ua732\\ua734\\ua736\\ua738\\ua73a\\ua73c\\ua73e' +\n '\\ua740\\ua742\\ua744\\ua746\\ua748\\ua74a\\ua74c\\ua74e\\ua750\\ua752\\ua754\\ua756\\ua758\\ua75a\\ua75c\\ua75e\\ua760\\ua762\\ua764\\ua766\\ua768\\ua76a\\ua76c\\ua76e\\ua779\\ua77b\\ua77d\\ua77e' +\n '\\ua780\\ua782\\ua784\\ua786\\ua78b\\ua78d\\ua790\\ua792\\ua7a0\\ua7a2\\ua7a4\\ua7a6\\ua7a8\\ua7aa';\n\nexports.txcite = ':((?:[^\\\\s()]|\\\\([^\\\\s()]+\\\\)|[()])+?)(?=[!-\\\\.:-@\\\\[\\\\\\\\\\\\]-`{-~]+(?:$|\\\\s)|$|\\\\s)';\n\nconst attr_class = exports.attr_class = '\\\\([^\\\\)]+\\\\)';\nconst attr_style = exports.attr_style = '\\\\{[^\\\\}]+\\\\}';\nconst attr_lang = exports.attr_lang = '\\\\[[^\\\\[\\\\]]+\\\\]';\nconst attr_align = exports.attr_align = '(?:<>|<|>|=)';\nconst attr_pad = exports.attr_pad = '[\\\\(\\\\)]+';\n\nconst txattr = exports.txattr = `(?:${ attr_class }|${ attr_style }|${ attr_lang }|${ attr_align }|${ attr_pad })*`;\n\nexports.txlisthd = `[\\\\t ]*[\\\\#\\\\*]*(\\\\*|\\\\#(?:_|\\\\d+)?)${ txattr }(?: \\\\S|\\\\.\\\\s*(?=\\\\S|\\\\n))`;\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/re_ext.js\n **/","/* textile list parser */\nconst ribbon = require( '../ribbon' );\nconst re = require( '../re' );\nconst merge = require( '../merge' );\n\nconst { parseAttr } = require( './attr' );\nconst { parsePhrase } = require( './phrase' );\n\nconst { txlisthd } = require( './re_ext' );\nre.pattern.txlisthd = txlisthd;\nconst reList = re.compile( /^((?:[:txlisthd:][^\\0]*?(?:\\r?\\n|$))+)(\\s*\\n|$)/, 's' );\nconst reItem = re.compile( /^([#\\*]+)([^\\0]+?)(\\n(?=[:txlisthd:])|$)/, 's' );\n\nfunction listPad ( n ) {\n let s = '\\n';\n while ( n-- ) {\n s += '\\t';\n }\n return s;\n}\n\nfunction testList ( src ) {\n return reList.exec( src );\n}\n\nfunction parseList ( src, options ) {\n src = ribbon( src.replace( /(^|\\r?\\n)[\\t ]+/, '$1' ) );\n\n const stack = [];\n const currIndex = {};\n const lastIndex = options._lst || {};\n let itemIndex = 0;\n let listAttr;\n let m;\n let n;\n let s;\n\n while ( ( m = reItem.exec( src ) ) ) {\n const item = [ 'li' ];\n const destLevel = m[1].length;\n const type = ( m[1].substr( -1 ) === '#' ) ? 'ol' : 'ul';\n let newLi = null;\n let lst;\n let par;\n let pba;\n let r;\n\n // list starts and continuations\n if ( ( n = /^(_|\\d+)/.exec( m[2] ) ) ) {\n itemIndex = isFinite( n[1] )\n ? parseInt( n[1], 10 )\n : lastIndex[ destLevel ] || currIndex[ destLevel ] || 1;\n m[2] = m[2].slice( n[1].length );\n }\n\n if ( ( pba = parseAttr( m[2], 'li' ) ) ) {\n m[2] = m[2].slice( pba[0] );\n pba = pba[1];\n }\n\n // list control\n if ( /^\\.\\s*$/.test( m[2] ) ) {\n listAttr = pba || {};\n src.advance( m[0] );\n continue;\n }\n\n // create nesting until we have correct level\n while ( stack.length < destLevel ) {\n // list always has an attribute object, this simplifies first-pba resolution\n lst = [ type, {}, listPad( stack.length + 1 ), ( newLi = [ 'li' ] ) ];\n par = stack[ stack.length - 1 ];\n if ( par ) {\n par.li.push( listPad( stack.length ) );\n par.li.push( lst );\n }\n stack.push({\n ul: lst,\n li: newLi,\n // count attributes's found per list\n att: 0\n });\n currIndex[ stack.length ] = 1;\n }\n\n // remove nesting until we have correct level\n while ( stack.length > destLevel ) {\n r = stack.pop();\n r.ul.push( listPad( stack.length ) );\n // lists have a predictable structure - move pba from listitem to list\n if ( r.att === 1 && !r.ul[3][1].substr ) {\n merge( r.ul[1], r.ul[3].splice( 1, 1 )[ 0 ] );\n }\n }\n\n // parent list\n par = stack[ stack.length - 1 ];\n\n if ( itemIndex ) {\n par.ul[1].start = itemIndex;\n currIndex[destLevel] = itemIndex;\n // falsy prevents this from fireing until it is set again\n itemIndex = 0;\n }\n if ( listAttr ) {\n // \"more than 1\" prevent attribute transfers on list close\n par.att = 9;\n merge( par.ul[1], listAttr );\n listAttr = null;\n }\n\n if ( !newLi ) {\n par.ul.push( listPad( stack.length ), item );\n par.li = item;\n }\n if ( pba ) {\n par.li.push( pba );\n par.att++;\n }\n Array.prototype.push.apply( par.li, parsePhrase( m[2].trim(), options ) );\n\n src.advance( m[0] );\n currIndex[destLevel] = ( currIndex[destLevel] || 0 ) + 1;\n }\n\n // remember indexes for continuations next time\n options._lst = currIndex;\n\n while ( stack.length ) {\n s = stack.pop();\n s.ul.push( listPad( stack.length ) );\n // lists have a predictable structure - move pba from listitem to list\n if ( s.att === 1 && !s.ul[3][1].substr ) {\n merge( s.ul[1], s.ul[3].splice( 1, 1 )[0] );\n }\n }\n\n return s.ul;\n}\n\nmodule.exports = {\n testList: testList,\n parseList: parseList\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/list.js\n **/","/* definitions list parser */\n\nconst ribbon = require( '../ribbon' );\n\nconst reDeflist = /^((?:- (?:[^\\n]\\n?)+?)+:=(?: *\\n[^\\0]+?=:(?:\\n|$)|(?:[^\\0]+?(?:$|\\n(?=\\n|- )))))+/;\nconst reItem = /^((?:- (?:[^\\n]\\n?)+?)+):=( *\\n[^\\0]+?=:\\s*(?:\\n|$)|(?:[^\\0]+?(?:$|\\n(?=\\n|- ))))/;\n\nfunction testDefList ( src ) {\n return reDeflist.exec( src );\n}\n\nfunction parseDefList ( src, options ) {\n src = ribbon( src.trim() );\n\n // late loading to get around the lack of non-circular-dependency support in RequireJS\n const parsePhrase = require( './phrase' ).parsePhrase;\n const parseFlow = require( './flow' ).parseFlow;\n\n const deflist = [ 'dl', '\\n' ];\n let terms;\n let def;\n let m;\n\n while ( ( m = reItem.exec( src ) ) ) {\n // add terms\n terms = m[1].split( /(?:^|\\n)\\- / ).slice( 1 );\n while ( terms.length ) {\n deflist.push( '\\t'\n , [ 'dt' ].concat( parsePhrase( terms.shift().trim(), options ) )\n , '\\n'\n );\n }\n // add definitions\n def = m[2].trim();\n deflist.push( '\\t'\n , [ 'dd' ].concat(\n ( /=:$/.test( def ) )\n ? parseFlow( def.slice( 0, -2 ).trim(), options )\n : parsePhrase( def, options )\n )\n , '\\n'\n );\n src.advance( m[0] );\n }\n return deflist;\n}\n\nexports.testDefList = testDefList;\nexports.parseDefList = parseDefList;\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/deflist.js\n **/","/* textile table parser */\n\nconst re = require( '../re' );\nconst merge = require( '../merge' );\nconst ribbon = require( '../ribbon' );\n\nconst { parseAttr } = require( './attr' );\nconst { parsePhrase } = require( './phrase' );\nconst { reIndent } = require( '../jsonml' );\n\nconst { txattr } = require( './re_ext' );\nre.pattern.txattr = txattr;\n\nconst reTable = re.compile( /^((?:table[:txattr:]\\.(?:\\s(.+?))\\s*\\n)?(?:(?:[:txattr:]\\.[^\\n\\S]*)?\\|.*?\\|[^\\n\\S]*(?:\\n|$))+)([^\\n\\S]*\\n)?/, 's' );\nconst reHead = /^table(_?)([^\\n]*?)\\.(?:[ \\t](.+?))?\\s*\\n/;\nconst reRow = re.compile( /^(?:\\|([~\\^\\-][:txattr:])\\.\\s*\\n)?([:txattr:]\\.[^\\n\\S]*)?\\|(.*?)\\|[^\\n\\S]*(\\n|$)/, 's' );\nconst reCaption = /^\\|=([^\\n+]*)\\n/;\nconst reColgroup = /^\\|:([^\\n+]*)\\|[\\r\\t ]*\\n/;\nconst reRowgroup = /^\\|([\\^\\-~])([^\\n+]*)\\.[ \\t\\r]*\\n/;\n\nconst charToTag = {\n '^': 'thead',\n '~': 'tfoot',\n '-': 'tbody'\n};\n\nfunction parseColgroup ( src ) {\n const colgroup = [ 'colgroup', {} ];\n src.split( '|' )\n .forEach( function ( s, isCol ) {\n const col = ( isCol ) ? {} : colgroup[ 1 ];\n let d = s.trim();\n let m;\n if ( d ) {\n if ( ( m = /^\\\\(\\d+)/.exec( d ) ) ) {\n col.span = +m[ 1 ];\n d = d.slice( m[ 0 ].length );\n }\n if ( ( m = parseAttr( d, 'col' ) ) ) {\n merge( col, m[ 1 ] );\n d = d.slice( m[ 0 ] );\n }\n if ( ( m = /\\b\\d+\\b/.exec( d ) ) ) {\n col.width = +m[0];\n }\n }\n if ( isCol ) {\n colgroup.push( '\\n\\t\\t', [ 'col', col ] );\n }\n });\n return colgroup.concat( [ '\\n\\t' ] );\n}\n\nfunction testTable ( src ) {\n return reTable.exec( src );\n}\n\nfunction parseTable ( src, options ) {\n src = ribbon( src.trim() );\n\n const rowgroups = [];\n let colgroup;\n let caption;\n const tAttr = {};\n let tCurr;\n let row;\n let inner;\n let pba;\n let more;\n let m;\n let extended = 0;\n\n const setRowGroup = function ( type, pba ) {\n tCurr = [ type, pba || {} ];\n rowgroups.push( tCurr );\n };\n\n if ( ( m = reHead.exec( src ) ) ) {\n // parse and apply table attr\n src.advance( m[0] );\n pba = parseAttr( m[2], 'table' );\n if ( pba ) {\n merge( tAttr, pba[1] );\n }\n if ( m[3] ) {\n tAttr.summary = m[3];\n }\n }\n\n // caption\n if ( ( m = reCaption.exec( src ) ) ) {\n caption = [ 'caption' ];\n if ( ( pba = parseAttr( m[1], 'caption' ) ) ) {\n caption.push( pba[1] );\n m[1] = m[1].slice( pba[0] );\n }\n if ( /\\./.test( m[1] ) ) { // mandatory \".\"\n caption.push( m[1].slice( 1 ).replace( /\\|\\s*$/, '' ).trim() );\n extended++;\n src.advance( m[0] );\n }\n else {\n caption = null;\n }\n }\n\n do {\n // colgroup\n if ( ( m = reColgroup.exec( src ) ) ) {\n colgroup = parseColgroup( m[1] );\n extended++;\n }\n // \"rowgroup\" (tbody, thead, tfoot)\n else if ( ( m = reRowgroup.exec( src ) ) ) {\n // PHP allows any amount of these in any order\n // and simply translates them straight through\n // the same is done here.\n const tag = charToTag[ m[1] ] || 'tbody';\n pba = parseAttr( `${ m[2] } `, tag );\n setRowGroup( tag, pba && pba[1] );\n extended++;\n }\n // row\n else if ( ( m = reRow.exec( src ) ) ) {\n if ( !tCurr ) { setRowGroup( 'tbody' ); }\n\n row = [ 'tr' ];\n\n if ( m[2] && ( pba = parseAttr( m[2], 'tr' ) ) ) {\n // FIXME: requires \"\\.\\s?\" -- else what ?\n row.push( pba[1] );\n }\n\n tCurr.push( '\\n\\t\\t', row );\n inner = ribbon( m[3] );\n\n do {\n inner.save();\n\n // cell loop\n const th = inner.startsWith( '_' );\n let cell = [ th ? 'th' : 'td' ];\n if ( th ) {\n inner.advance( 1 );\n }\n\n pba = parseAttr( inner, 'td' );\n if ( pba ) {\n inner.advance( pba[0] );\n cell.push( pba[1] ); // FIXME: don't do this if next text fails\n }\n\n if ( pba || th ) {\n const p = /^\\.\\s*/.exec( inner );\n if ( p ) {\n inner.advance( p[0] );\n }\n else {\n cell = [ 'td' ];\n inner.load();\n }\n }\n\n const mx = /^(==.*?==|[^\\|])*/.exec( inner );\n cell = cell.concat( parsePhrase( mx[0], options ) );\n row.push( '\\n\\t\\t\\t', cell );\n more = inner.valueOf().charAt( mx[0].length ) === '|';\n inner.advance( mx[0].length + 1 );\n }\n while ( more );\n\n row.push( '\\n\\t\\t' );\n }\n //\n if ( m ) {\n src.advance( m[0] );\n }\n }\n while ( m );\n\n // assemble table\n let table = [ 'table', tAttr ];\n if ( extended ) {\n if ( caption ) {\n table.push( '\\n\\t', caption );\n }\n if ( colgroup ) {\n table.push( '\\n\\t', colgroup );\n }\n rowgroups.forEach( function ( tbody ) {\n table.push( '\\n\\t', tbody.concat( [ '\\n\\t' ] ) );\n });\n }\n else {\n table = table.concat( reIndent( rowgroups[0].slice( 2 ), -1 ) );\n }\n\n table.push( '\\n' );\n return table;\n}\n\nmodule.exports = {\n parseColgroup: parseColgroup,\n parseTable: parseTable,\n testTable: testTable\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/table.js\n **/"],"sourceRoot":""} \ No newline at end of file diff --git a/dist/textile.min.js b/dist/textile.min.js new file mode 100644 index 0000000..522a548 --- /dev/null +++ b/dist/textile.min.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("textile",[],t):"object"==typeof exports?exports.textile=t():e.textile=t()}(this,function(){return function(e){function t(r){if(n[r])return n[r].exports;var s=n[r]={exports:{},id:r,loaded:!1};return e[r].call(s.exports,s,s.exports,t),s.loaded=!0,s.exports}var n={};return t.m=e,t.c=n,t.p="",t(0)}([function(e,t,n){"use strict";function r(e,t){return t=s(s({},r.defaults),t||{}),l(e,t).map(i).join("")}var s=n(1),a=n(2),i=a.toHTML,c=n(6),l=c.parseFlow,o=n(3),p=o.parseHtml;e.exports=r,r.defaults={breaks:!0},r.setOptions=r.setoptions=function(e){return s(r.defaults,e),this},r.parse=r.convert=r,r.html_parser=p,r.jsonml=function(e,t){return t=s(s({},r.defaults),t||{}),["html"].concat(l(e,t))},r.serialize=i},function(e,t){"use strict";e.exports=function(e,t){if(t)for(var n in t)e[n]=t[n];return e}},function(e,t,n){"use strict";function r(e,t){return t?e.map(function(e){if(/^\n\t+/.test(e))if(0>t)e=e.slice(0,t);else for(var n=0;t>n;n++)e+=" ";else if(Array.isArray(e))return r(e,t);return e}):e}function s(e,t){return e.replace(/&(?!(#\d{2,}|#x[\da-fA-F]{2,}|[a-zA-Z][a-zA-Z1-4]{1,6});)/g,"&").replace(//g,">").replace(/"/g,t?""":'"').replace(/'/g,t?"'":"'")}function a(e){if(e=e.concat(),"string"==typeof e)return s(e);var t=e.shift(),n={},r="",l=[];for(e.length&&"object"===i(e[0])&&!Array.isArray(e[0])&&(n=e.shift());e.length;)l.push(a(e.shift()));for(var o in n)r+=null==n[o]?" "+o:" "+o+'="'+s(String(n[o]),!0)+'"';return"!"===t?"":t in c?"<"+t+r+" />":"<"+t+r+">"+l.join("")+""}var i="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e},c=n(3).singletons;e.exports={reIndent:r,toHTML:a,escape:s}},function(e,t,n){"use strict";function r(){return!0}function s(e){return f.exec(e)}function a(e){return g.exec(e)}function i(e){return v.exec(e)}function c(e){return h.exec(e)}function l(e){for(var t={},n=void 0;n=d.exec(e);)t[n[1]]="string"==typeof n[2]?n[2].replace(/^(["'])(.*)\1$/,"$2"):null,e=e.slice(n[0].length);return t}function o(e,t){var n=[],a=n,o=[],p=t?function(e){return e in t}:r,d=void 0,f=void 0;e="string"==typeof e?u(e):e;do if((d=s(e))&&p("!"))e.advance(d[0]),a.push(["!",d[1]]);else if((d=c(e))&&p(d[1])){if(f=d[1],o.length)for(var h=o.length-1;h>=0;h--){var v=o[h];if(v[0]===f){o.splice(h),a=o[o.length-1]||n;break}}e.advance(d[0])}else if((d=i(e))&&p(d[1])){e.advance(d[0]),f=d[1];var g=d[3]||d[1]in x,m=d[4],b=[f];d[2]&&b.push(l(d[2])),g?(a.push(b),m&&a.push(m)):(m&&b.push(m),o.push(b),a.push(b),a=b)}else d=/([^<]+|[^\0])/.exec(e),d&&a.push(d[0]),e.advance(d?d[0].length||1:1);while(e.valueOf());return n}var p=n(4),u=n(5);p.pattern.html_id="[a-zA-Z][a-zA-Z\\d:]*",p.pattern.html_attr="(?:\"[^\"]+\"|'[^']+'|[^>\\s]+)";var d=p.compile(/^\s*([^=\s]+)(?:\s*=\s*("[^"]+"|'[^']+'|[^>\s]+))?/),f=p.compile(/^/,"s"),h=p.compile(/^<\/([:html_id:])([^>]*)>/),v=p.compile(/^<([:html_id:])((?:\s[^=\s\/]+(?:\s*=\s*[:html_attr:])?)+)?\s*(\/?)>(\n*)/),g=p.compile(/^\s*<([:html_id:](?::[a-zA-Z\d]+)*)((?:\s[^=\s\/]+(?:\s*=\s*[:html_attr:])?)+)?\s*(\/?)>(\n*)/),x={br:1,hr:1,img:1,link:1,meta:1,wbr:1,area:1,param:1,input:1,option:1,base:1,col:1};e.exports={singletons:x,parseHtml:o,parseHtmlAttr:l,testCloseTag:c,testOpenTagBlock:a,testOpenTag:i,testComment:s}},function(e,t){"use strict";var n={},r=e.exports={pattern:{punct:"[!-/:-@\\[\\\\\\]-`{-~]",space:"\\s"},escape:function(e){return e.replace(/[\-\[\]\{\}\(\)\*\+\?\.,\\\^\$\|#\s]/g,"\\$&")},collapse:function(e){return e.replace(/(?:#.*?(?:\n|$))/g,"").replace(/\s+/g,"")},expandPatterns:function(e){return e.replace(/\[:\s*(\w+)\s*:\]/g,function(t,n){var s=r.pattern[n];if(s)return r.expandPatterns(s);throw new Error("Pattern "+t+" not found in "+e)})},isRegExp:function(e){return"[object RegExp]"===Object.prototype.toString.call(e)},compile:function(e,t){r.isRegExp(e)&&(1===arguments.length&&(t=(e.global?"g":"")+(e.ignoreCase?"i":"")+(e.multiline?"m":"")),e=e.source);var s=e+(t||"");if(s in n)return n[s];var a=r.expandPatterns(e);return t&&/x/.test(t)&&(a=r.collapse(a)),t&&/s/.test(t)&&(a=a.replace(/([^\\])\./g,"$1[^\\0]")),t=(t||"").replace(/[^gim]/g,""),n[s]=new RegExp(a,t)}}},function(e,t){"use strict";e.exports=function(e){var t=String(e),n=null,r=0;return{save:function(){n=r},load:function(){r=n,e=t.slice(r),this.$=e},advance:function(n){return r+="string"==typeof n?n.length:n,e=t.slice(r),this.$=e,e},lookbehind:function(e){return e=null==e?1:e,t.slice(r-e,r)},startsWith:function(t){return e.substring(0,t.length)===t},valueOf:function(){return this.$=e,e},toString:function(){return this.$=e,e}}}},function(e,t,n){"use strict";function r(e,t,n,r,s){t=t||"p";var a=[];return e.split(/(?:\r?\n){2,}/).forEach(function(e,i){"p"===t&&/^\s/.test(e)?(e=e.replace(/\r?\n[\t ]/g," ").trim(),a=a.concat(g(e,s))):(r&&i&&a.push(r),a.push(n?[t,n].concat(g(e,s)):[t].concat(g(e,s))))}),a}function s(e,t){var n=a(),o=void 0,v=void 0;for(e=i(e.replace(/^( *\r?\n)+/,""));e.valueOf();)if(e.save(),v=R.exec(e))o||(o={}),e.advance(v[0]),o[v[1]]=v[2];else{if(n.linebreak(),v=C.exec(e)){e.advance(v[0]);var x=v[0],y=b(e,x);if(y&&(e.advance(y[0]),y=y[1]),v=/^\.(\.?)(?:\s|(?=:))/.exec(e)){var S=!!v[1],k=S?Z:H;if(v=k.exec(e.advance(v[0])),e.advance(v[0]),"bq"===x){var O=v[1];(v=/^:(\S+)\s+/.exec(O))&&(y||(y={}),y.cite=v[1],O=O.slice(v[0].length));var L=r(O,"p",m(y,{cite:1,id:1}),"\n",t);n.add(["blockquote",y,"\n"].concat(L).concat(["\n"]))}else if("bc"===x){var E=y?m(y,{id:1}):null;n.add(["pre",y,E?["code",E,v[1]]:["code",v[1]]])}else if("notextile"===x)n.merge(p(v[1]));else if("###"===x);else if("pre"===x)n.add(["pre",y,v[1]]);else if(D.test(x)){var P=x.replace(/\D+/g,"");y||(y={}),y["class"]=(y["class"]?y["class"]+" ":"")+"footnote",y.id="fn"+P,n.add(["p",y,["a",{href:"#fnr"+P},["sup",P]]," "].concat(g(v[1],t)))}else n.merge(r(v[1],x,y,"\n",t));continue}e.load()}if(v=f(e))e.advance(v[0]+(/(?:\s*\n+)+/.exec(e)||[])[0]),n.add(["!",v[1]]);else{if(v=h(e)){var F=v[1],M=v[3]||F in d,W=v[4];if(F in z){e.advance(v[0]);var I=[F];if(v[2]&&I.push(u(v[2])),M){n.add(I);continue}var B=c.compile("^(.*?)(\\s*)()(\\s*)","s");if(v=B.exec(e)){e.advance(v[0]),"pre"===F?(I.push(W),I=I.concat(p(v[1].replace(/(\r?\n)+$/,""),{code:1})),v[2]&&I.push(v[2]),n.add(I)):"notextile"===F?(I=p(v[1].trim()),n.merge(I)):"script"===F||"noscript"===F?(I.push(W+v[1]),n.add(I)):(/\n/.test(W)&&I.push("\n"),I=/\n/.test(v[1])?I.concat(s(v[1],t)):I.concat(g(v[1].replace(/^ +/,""),t)),/\n/.test(v[2])&&I.push("\n"),n.add(I));continue}}e.load()}(v=q.exec(e))?(e.advance(v[0]),n.add(["hr"])):(v=$(e))?(e.advance(v[0]),n.add(A(v[0],t))):(v=_(e))?(e.advance(v[0]),n.add(w(v[0],t))):(v=j(e))?(e.advance(v[0]),n.add(T(v[1],t))):(v=H.exec(e),n.merge(r(v[1],"p",void 0,"\n",t)),e.advance(v[0]))}}return o?l(n.get(),o):n.get()}var a=n(7),i=n(5),c=n(4),l=n(8),o=n(3),p=o.parseHtml,u=o.parseHtmlAttr,d=o.singletons,f=o.testComment,h=o.testOpenTagBlock,v=n(9),g=v.parsePhrase,x=n(10),m=x.copyAttr,b=x.parseAttr,y=n(13),$=y.testList,A=y.parseList,S=n(14),_=S.testDefList,w=S.parseDefList,k=n(15),j=k.testTable,T=k.parseTable,O=n(12),L=O.txblocks,E=O.txlisthd,P=O.txattr;c.pattern.txblocks=L,c.pattern.txlisthd=E,c.pattern.txattr=P;var z={p:0,hr:0,ul:1,ol:0,li:0,div:1,pre:0,object:1,script:0,noscript:0,blockquote:1,notextile:1},C=c.compile(/^([:txblocks:])/),H=c.compile(/^(.*?)($|\r?\n(?=[:txlisthd:])|\r?\n(?:\s*\n|$)+)/,"s"),Z=c.compile(/^(.*?)($|\r?\n(?=[:txlisthd:])|\r?\n+(?=[:txblocks:][:txattr:]\.))/,"s"),q=/^(\-\-\-+|\*\*\*+|___+)(\r?\n\s+|$)/,R=c.compile(/^\[([^\]]+)\]((?:https?:\/\/|\/)\S+)(?:\s*\n|$)/),D=/^fn\d+$/;t.parseFlow=s},function(e,t){"use strict";e.exports=function(e){var t=Array.isArray(e)?e:[];return{add:function(e){return"string"==typeof e&&"string"==typeof t[t.length-1]?t[t.length-1]+=e:Array.isArray(e)?t.push(e.filter(function(e){return void 0!==e})):e&&t.push(e),this},merge:function(e){for(var t=0,n=e.length;n>t;t++)this.add(e[t]);return this},linebreak:function(){t.length&&this.add("\n")},get:function(){return t}}}},function(e,t){"use strict";var n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol?"symbol":typeof e};e.exports=function r(e,t){if(Array.isArray(e)){if("a"===e[0]){var s=e[1];"object"===("undefined"==typeof s?"undefined":n(s))&&"href"in s&&s.href in t&&(s.href=t[s.href])}for(var a=0,i=e.length;i>a;a++)Array.isArray(e[a])&&r(e[a],t)}return e}},function(e,t,n){"use strict";function r(e,t){e=s(e);var n=a(),c=void 0,o=void 0;do if(e.save(),e.startsWith("\r\n")&&e.advance(1),e.startsWith("\n"))e.advance(1),t.breaks&&n.add(["br"]),n.add("\n");else if(c=/^==(.*?)==/.exec(e))e.advance(c[0]),n.add(c[1]);else{var u=e.lookbehind(1),g=!u||/^[\s>.,"'?!;:()]$/.test(u);if((c=$.exec(e))&&(g||c[1])){e.advance(c[0]);var x=c[2],m=c[1],b=y[x],O="code"===b;(o=!O&&l(e,b,x))&&(e.advance(o[0]),o=o[1]);var L=void 0,E=void 0;if("["===m)L="^(.*?)",E="(?:])";else if("{"===m)L="^(.*?)",E="(?:})";else{var P=i.escape(x.charAt(0));L=O?"^(\\S+|\\S+.*?\\S)":"^([^\\s"+P+"]+|[^\\s"+P+"].*?\\S("+P+"*))",E="(?=$|[\\s.,\"'!?;:()«»„“”‚‘’])"}var z=i.compile(L+"("+i.escape(x)+")"+E);if((c=z.exec(e))&&c[1]){e.advance(c[0]),O?n.add([b,c[1]]):n.add([b,o].concat(r(c[1],t)));continue}e.load()}if((c=A.exec(e))||(c=S.exec(e))){e.advance(c[0]),o=c[1]&&l(c[1],"img");var C=o?o[1]:{src:""},H=["img",C];C.src=c[2],C.alt=c[3]?C.title=c[3]:"",c[4]&&(H=["a",{href:c[4]},H]),n.add(H)}else if(c=h(e))e.advance(c[0]),n.add(["!",c[1]]);else{if(c=v(e)){e.advance(c[0]);var Z=c[1],q=c[3]||c[1]in f,R=[Z],D=c[4];if(c[2]&&R.push(d(c[2])),q){n.add(R).add(D);continue}var F=i.compile("^(.*?)()","s");if(c=F.exec(e)){if(e.advance(c[0]),"code"===Z)R.push(D,c[1]);else{if("notextile"===Z){n.merge(r(c[1],t));continue}R=R.concat(r(c[1],t))}n.add(R);continue}e.load()}if((c=T.exec(e))&&/\S/.test(u))e.advance(c[0]),n.add(["sup",{"class":"footnote",id:"fnr"+c[1]},"!"===c[2]?c[1]:["a",{href:"#fn"+c[1]},c[1]]]);else if(c=_.exec(e)){e.advance(c[0]);var M=["span",{"class":"caps"},c[1]];c[2]&&(M=["acronym",{title:c[2]},M]),n.add(M)}else if(g&&(c=w.exec(e))||(c=k.exec(e))){e.advance(c[0]);var W=c[1].match(j),I=W?c[1].slice(0,c[1].length-W[0].length):c[1];(o=l(I,"a"))?(I=I.slice(o[0]),o=o[1]):o={},W&&!I&&(I=W[0],W=""),o.href=c[2],W&&(o.title=W[1]),n.add(["a",o].concat(r(I.replace(/^(\.?\s*)/,""),t)))}else c=/([a-zA-Z0-9,.':]+|[ \f\r\t\v\xA0\u2028\u2029]+|[^\0])/.exec(e),c&&n.add(c[0]),e.advance(c?c[0].length||1:1)}}while(e.valueOf());return n.get().map(p)}var s=n(5),a=n(7),i=n(4),c=n(10),l=c.parseAttr,o=n(11),p=o.parseGlyph,u=n(3),d=u.parseHtmlAttr,f=u.singletons,h=u.testComment,v=u.testOpenTag,g=n(12),x=g.ucaps,m=g.txattr,b=g.txcite;i.pattern.txattr=m,i.pattern.txcite=b,i.pattern.ucaps=x;var y={"*":"strong","**":"b","??":"cite",_:"em",__:"i","-":"del","%":"span","+":"ins","~":"sub","^":"sup","@":"code"},$=/^([\[\{]?)(__?|\*\*?|\?\?|[\-\+\^~@%])/,A=i.compile(/^!(?!\s)([:txattr:](?:\.[^\n\S]|\.(?:[^\.\/]))?)([^!\s]+?) ?(?:\(((?:[^\(\)]+|\([^\(\)]+\))+)\))?!(?::([^\s]+?(?=[!-\.:-@\[\\\]-`{-~](?:$|\s)|\s|$)))?/),S=i.compile(/^\[!(?!\s)([:txattr:](?:\.[^\n\S]|\.(?:[^\.\/]))?)([^!\s]+?) ?(?:\(((?:[^\(\)]+|\([^\(\)]+\))+)\))?!(?::([^\s]+?(?=[!-\.:-@\[\\\]-`{-~](?:$|\s)|\s|$)))?\]/),_=i.compile(/^((?!TM\)|tm\))[[:ucaps:]](?:[[:ucaps:]\d]{1,}(?=\()|[[:ucaps:]\d]{2,}))(?:\((.*?)\))?(?=\W|$)/),w=i.compile(/^"(?!\s)((?:[^\n"]|"(?![\s:])[^\n"]+"(?!:))+)"[:txcite:]/),k=/^\["([^\n]+?)":((?:\[[a-z0-9]*\]|[^\]])+)\]/,j=/\s*\(((?:\([^\(\)]*\)|[^\(\)])+)\)$/,T=/^\[(\d+)(!?)\]/;t.parsePhrase=r},function(e,t){"use strict";function n(e,t){if(e){var n={};for(var r in e)!(r in e)||t&&r in t||(n[r]=e[r]);return n}}function r(e){return/^(?:table|t[dh]|t(?:foot|head|body)|b[qc]|div|notextile|pre|h[1-6]|fn\\d+|p|###)$/.test(e)}function s(e,t,n){if(e=String(e),e&&"notextile"!==t){var s=void 0,m={},b={style:m},y=e,$=r(t),A="img"===t,S="li"===t,_=!$&&!A&&"a"!==t,w=A?o:l;do if(s=f.exec(y))s[1].split(";").forEach(function(e){var t=e.match(h);t&&(m[t[1]]=t[2])}),y=y.slice(s[0].length);else if(s=v.exec(y)){var k=y.slice(s[0].length);!k&&_||n&&n===k.slice(0,n.length)?s=null:(b.lang=s[1],y=y.slice(s[0].length))}else if(s=a.exec(y)){var j=y.slice(s[0].length);if(!j&&_||n&&(" "===j[0]||n===j.slice(0,n.length)))s=null;else{var T=s[1].split("#");T[0]&&(b["class"]=T[0]),T[1]&&(b.id=T[1]),y=j}}else{if($||S){if(s=i.exec(y)){m["padding-left"]=s[1].length+"em",y=y.slice(s[0].length);continue}if(s=c.exec(y)){m["padding-right"]=s[1].length+"em",y=y.slice(s[0].length);continue}}if((A||$||S)&&(s=w.exec(y))){var O=g[s[1]];A?b.align=O:m["text-align"]=O,y=y.slice(s[0].length)}else if("td"!==t&&"tr"!==t||!(s=p.exec(y))){if("td"===t){if(s=u.exec(y)){b.colspan=s[1],y=y.slice(s[0].length);continue}if(s=d.exec(y)){b.rowspan=s[1],y=y.slice(s[0].length);continue}}}else m["vertical-align"]=x[s[1]],y=y.slice(s[0].length)}while(s);var L=[];for(var E in m)L.push(E+":"+m[E]);return L.length?b.style=L.join(";"):delete b.style,y===e?void 0:[e.length-y.length,b]}}var a=/^\(([^\(\)\n]+)\)/,i=/^(\(+)/,c=/^(\)+)/,l=/^(<>|<|>|=)/,o=/^(<|>|=)/,p=/^(~|\^|\-)/,u=/^\\(\d+)/,d=/^\/(\d+)/,f=/^\{([^\}]*)\}/,h=/^\s*([^:\s]+)\s*:\s*(.+)\s*$/,v=/^\[([^\[\]\n]+)\]/,g={"<":"left","=":"center",">":"right","<>":"justify"},x={"~":"bottom","^":"top","-":"middle"};e.exports={copyAttr:n,parseAttr:s}},function(e,t,n){"use strict";var r=n(4),s=/(\w)'(\w)/g,a=/([^\-]|^)->/,i=r.compile(/([^\s\[\(])"(?=$|\s|[:punct:])/g),c=r.compile(/([^\s\[\(])'(?=$|\s|[:punct:])/g),l=/(\b ?|\s|^)(?:\(C\)|\[C\])/gi,o=/([\d\.,]+['"]? ?)x( ?)(?=[\d\.,]['"]?)/g,p=r.compile(/(\d*[\.,]?\d+)"(?=\s|$|[:punct:])/g),u=/([^.]?)\.{3}/g,d=/(^|[\s\w])--([\s\w]|$)/g,f=/ - /g,h=/"/g,v=/'/g,g=/(\b ?|\s|^)(?:\(R\)|\[R\])/gi,x=r.compile(/(\d*[\.,]?\d+)'(?=\s|$|[:punct:])/g),m=/(\b ?|\s|^)(?:\((?:TM|tm)\)|\[(?:TM|tm)\])/g;t.parseGlyph=function(e){return"string"!=typeof e?e:e.replace(a,"$1→").replace(o,"$1×$2").replace(u,"$1…").replace(d,"$1—$2").replace(f," – ").replace(m,"$1™").replace(g,"$1®").replace(l,"$1©").replace(p,"$1″").replace(i,"$1”").replace(h,"“").replace(x,"$1′").replace(s,"$1’$2").replace(c,"$1’").replace(v,"‘").replace(/[\(\[]1\/4[\]\)]/,"¼").replace(/[\(\[]1\/2[\]\)]/,"½").replace(/[\(\[]3\/4[\]\)]/,"¾").replace(/[\(\[]o[\]\)]/,"°").replace(/[\(\[]\+\/\-[\]\)]/,"±")}},function(e,t){"use strict";t.txblocks="(?:b[qc]|div|notextile|pre|h[1-6]|fn\\d+|p|###)",t.ucaps="A-ZÀ-ÖØ-ÞĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮİIJĴĶĹĻĽĿŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŸŹŻŽƁƂƄƆƇƉ-ƋƎ-ƑƓƔƖ-ƘƜƝƟƠƢƤƦƧƩƬƮƯƱ-ƳƵƷƸƼDŽLJNJǍǏǑǓǕǗǙǛǞǠǢǤǦǨǪǬǮDZǴǶ-ǸǺǼǾȀȂȄȆȈȊȌȎȐȒȔȖȘȚȜȞȠȢȤȦȨȪȬȮȰȲȺȻȽȾɁɃ-ɆɈɊɌɎḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾẀẂẄẆẈẊẌẎẐẒẔẞẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸỺỼỾⱠⱢ-ⱤⱧⱩⱫⱭ-ⱰⱲⱵⱾⱿꜢꜤꜦꜨꜪꜬꜮꜲꜴꜶꜸꜺꜼꜾꝀꝂꝄꝆꝈꝊꝌꝎꝐꝒꝔꝖꝘꝚꝜꝞꝠꝢꝤꝦꝨꝪꝬꝮꝹꝻꝽꝾꞀꞂꞄꞆꞋꞍꞐꞒꞠꞢꞤꞦꞨꞪ",t.txcite=":((?:[^\\s()]|\\([^\\s()]+\\)|[()])+?)(?=[!-\\.:-@\\[\\\\\\]-`{-~]+(?:$|\\s)|$|\\s)";var n=t.attr_class="\\([^\\)]+\\)",r=t.attr_style="\\{[^\\}]+\\}",s=t.attr_lang="\\[[^\\[\\]]+\\]",a=t.attr_align="(?:<>|<|>|=)",i=t.attr_pad="[\\(\\)]+",c=t.txattr="(?:"+n+"|"+r+"|"+s+"|"+a+"|"+i+")*";t.txlisthd="[\\t ]*[\\#\\*]*(\\*|\\#(?:_|\\d+)?)"+c+"(?: \\S|\\.\\s*(?=\\S|\\n))"},function(e,t,n){"use strict";function r(e){for(var t="\n";e--;)t+=" ";return t}function s(e){return v.exec(e)}function a(e,t){e=i(e.replace(/(^|\r?\n)[\t ]+/,"$1"));for(var n=[],s={},a=t._lst||{},c=0,o=void 0,u=void 0,f=void 0,h=void 0;u=g.exec(e);){var v=["li"],x=u[1].length,m="#"===u[1].substr(-1)?"ol":"ul",b=null,y=void 0,$=void 0,A=void 0,S=void 0;if((f=/^(_|\d+)/.exec(u[2]))&&(c=isFinite(f[1])?parseInt(f[1],10):a[x]||s[x]||1,u[2]=u[2].slice(f[1].length)),(A=p(u[2],"li"))&&(u[2]=u[2].slice(A[0]),A=A[1]),/^\.\s*$/.test(u[2]))o=A||{},e.advance(u[0]);else{for(;n.lengthx;)S=n.pop(),S.ul.push(r(n.length)),1!==S.att||S.ul[3][1].substr||l(S.ul[1],S.ul[3].splice(1,1)[0]);$=n[n.length-1],c&&($.ul[1].start=c,s[x]=c,c=0),o&&($.att=9,l($.ul[1],o),o=null),b||($.ul.push(r(n.length),v),$.li=v),A&&($.li.push(A),$.att++),Array.prototype.push.apply($.li,d(u[2].trim(),t)),e.advance(u[0]),s[x]=(s[x]||0)+1}}for(t._lst=s;n.length;)h=n.pop(),h.ul.push(r(n.length)),1!==h.att||h.ul[3][1].substr||l(h.ul[1],h.ul[3].splice(1,1)[0]);return h.ul}var i=n(5),c=n(4),l=n(1),o=n(10),p=o.parseAttr,u=n(9),d=u.parsePhrase,f=n(12),h=f.txlisthd;c.pattern.txlisthd=h;var v=c.compile(/^((?:[:txlisthd:][^\0]*?(?:\r?\n|$))+)(\s*\n|$)/,"s"),g=c.compile(/^([#\*]+)([^\0]+?)(\n(?=[:txlisthd:])|$)/,"s");e.exports={testList:s,parseList:a}},function(e,t,n){"use strict";function r(e){return i.exec(e)}function s(e,t){e=a(e.trim());for(var r=n(9).parsePhrase,s=n(6).parseFlow,i=["dl","\n"],l=void 0,o=void 0,p=void 0;p=c.exec(e);){for(l=p[1].split(/(?:^|\n)\- /).slice(1);l.length;)i.push(" ",["dt"].concat(r(l.shift().trim(),t)),"\n");o=p[2].trim(),i.push(" ",["dd"].concat(/=:$/.test(o)?s(o.slice(0,-2).trim(),t):r(o,t)),"\n"),e.advance(p[0])}return i}var a=n(5),i=/^((?:- (?:[^\n]\n?)+?)+:=(?: *\n[^\0]+?=:(?:\n|$)|(?:[^\0]+?(?:$|\n(?=\n|- )))))+/,c=/^((?:- (?:[^\n]\n?)+?)+):=( *\n[^\0]+?=:\s*(?:\n|$)|(?:[^\0]+?(?:$|\n(?=\n|- ))))/;t.testDefList=r,t.parseDefList=s},function(e,t,n){"use strict";function r(e){var t=["colgroup",{}];return e.split("|").forEach(function(e,n){var r=n?{}:t[1],s=e.trim(),a=void 0;s&&((a=/^\\(\d+)/.exec(s))&&(r.span=+a[1],s=s.slice(a[0].length)),(a=p(s,"col"))&&(c(r,a[1]),s=s.slice(a[0])),(a=/\b\d+\b/.exec(s))&&(r.width=+a[0])),n&&t.push("\n ",["col",r])}),t.concat(["\n "])}function s(e){return x.exec(e)}function a(e,t){e=l(e.trim());var n=[],s=void 0,a=void 0,i={},o=void 0,u=void 0,f=void 0,v=void 0,g=void 0,x=void 0,_=0,w=function(e,t){o=[e,t||{}],n.push(o)};(x=m.exec(e))&&(e.advance(x[0]),v=p(x[2],"table"),v&&c(i,v[1]),x[3]&&(i.summary=x[3])),(x=y.exec(e))&&(a=["caption"],(v=p(x[1],"caption"))&&(a.push(v[1]),x[1]=x[1].slice(v[0])),/\./.test(x[1])?(a.push(x[1].slice(1).replace(/\|\s*$/,"").trim()),_++,e.advance(x[0])):a=null);do{if(x=$.exec(e))s=r(x[1]),_++;else if(x=A.exec(e)){var k=S[x[1]]||"tbody";v=p(x[2]+" ",k),w(k,v&&v[1]),_++}else if(x=b.exec(e)){o||w("tbody"),u=["tr"],x[2]&&(v=p(x[2],"tr"))&&u.push(v[1]),o.push("\n ",u),f=l(x[3]);do{f.save();var j=f.startsWith("_"),T=[j?"th":"td"];if(j&&f.advance(1),v=p(f,"td"),v&&(f.advance(v[0]),T.push(v[1])),v||j){var O=/^\.\s*/.exec(f);O?f.advance(O[0]):(T=["td"],f.load())}var L=/^(==.*?==|[^\|])*/.exec(f);T=T.concat(d(L[0],t)),u.push("\n ",T),g="|"===f.valueOf().charAt(L[0].length),f.advance(L[0].length+1)}while(g);u.push("\n ")}x&&e.advance(x[0])}while(x);var E=["table",i];return _?(a&&E.push("\n ",a),s&&E.push("\n ",s),n.forEach(function(e){E.push("\n ",e.concat(["\n "]))})):E=E.concat(h(n[0].slice(2),-1)),E.push("\n"),E}var i=n(4),c=n(1),l=n(5),o=n(10),p=o.parseAttr,u=n(9),d=u.parsePhrase,f=n(2),h=f.reIndent,v=n(12),g=v.txattr;i.pattern.txattr=g;var x=i.compile(/^((?:table[:txattr:]\.(?:\s(.+?))\s*\n)?(?:(?:[:txattr:]\.[^\n\S]*)?\|.*?\|[^\n\S]*(?:\n|$))+)([^\n\S]*\n)?/,"s"),m=/^table(_?)([^\n]*?)\.(?:[ \t](.+?))?\s*\n/,b=i.compile(/^(?:\|([~\^\-][:txattr:])\.\s*\n)?([:txattr:]\.[^\n\S]*)?\|(.*?)\|[^\n\S]*(\n|$)/,"s"),y=/^\|=([^\n+]*)\n/,$=/^\|:([^\n+]*)\|[\r\t ]*\n/,A=/^\|([\^\-~])([^\n+]*)\.[ \t\r]*\n/,S={"^":"thead","~":"tfoot","-":"tbody"};e.exports={parseColgroup:r,parseTable:a,testTable:s}}])}); +//# sourceMappingURL=textile.min.js.map \ No newline at end of file diff --git a/dist/textile.min.js.map b/dist/textile.min.js.map new file mode 100644 index 0000000..3dcb4a7 --- /dev/null +++ b/dist/textile.min.js.map @@ -0,0 +1 @@ +{"version":3,"sources":["webpack:///webpack/universalModuleDefinition","webpack:///textile.min.js","webpack:///webpack/bootstrap 993a960178192ed49935","webpack:///./src/index.js","webpack:///./src/merge.js","webpack:///./src/jsonml.js","webpack:///./src/html.js","webpack:///./src/re.js","webpack:///./src/ribbon.js","webpack:///./src/textile/flow.js","webpack:///./src/builder.js","webpack:///./src/fixlinks.js","webpack:///./src/textile/phrase.js","webpack:///./src/textile/attr.js","webpack:///./src/textile/glyph.js","webpack:///./src/textile/re_ext.js","webpack:///./src/textile/list.js","webpack:///./src/textile/deflist.js","webpack:///./src/textile/table.js"],"names":["root","factory","exports","module","define","amd","this","modules","__webpack_require__","moduleId","installedModules","id","loaded","call","m","c","p","textile","txt","opt","merge","defaults","parseFlow","map","toHTML","join","_require","_require2","_require3","parseHtml","breaks","setOptions","setoptions","parse","convert","html_parser","jsonml","concat","serialize","a","b","k","reIndent","ml","shiftBy","s","test","slice","i","Array","isArray","escape","text","escapeQuotes","replace","tag","shift","attributes","tagAttrs","content","length","_typeof","push","String","singletons","Symbol","iterator","obj","constructor","allowAll","testComment","src","reComment","exec","testOpenTagBlock","reHtmlTagBlock","testOpenTag","reTag","testCloseTag","reEndTag","parseHtmlAttr","attrSrc","attr","reAttr","whitelistTags","list","_stack","oktag","ribbon","advance","head","splice","single","tail","element","valueOf","re","pattern","html_id","html_attr","compile","br","hr","img","link","meta","wbr","area","param","input","option","base","col","_cache","punct","space","collapse","expandPatterns","ex","Error","isRegExp","r","Object","prototype","toString","flags","arguments","global","ignoreCase","multiline","source","ckey","rx","RegExp","feed","org","slot","pos","save","load","$","n","lookbehind","nchars","startsWith","substring","paragraph","pba","linebreak","options","out","split","forEach","bit","trim","parsePhrase","builder","linkRefs","reLinkRef","reBlock","blockType","parseAttr","extended","reBlockGlob","reBlockExtended","reBlockNormal","inner","cite","par","copyAttr","add","subPba","reFootnoteDef","fnid","href","allowedBlocktags","code","reRuler","testList","parseList","testDefList","parseDefList","testTable","parseTable","undefined","fixLinks","get","_require4","_require5","_require6","_require7","txblocks","txlisthd","txattr","ul","ol","li","div","pre","object","script","noscript","blockquote","notextile","initArr","arr","node","filter","l","dict","behind","boundary","rePhrase","tok","fence","phraseType","phraseConvert","mMid","mEnd","t1","charAt","reImage","reImageFenced","alt","title","reFootnote","class","reCaps","caps","reLink","reLinkFenced","match","reLinkTitle","parseGlyph","ucaps","txcite","*","**","??","_","__","-","%","+","~","^","@","blacklist","d","testBlock","name","endToken","st","o","style","remaining","isBlock","isImg","isList","isPhrase","reAlign","reAlignImg","reAlignBlock","reStyles","reCSS","reLang","rm","reClassid","_rm","bits","rePaddingL","rePaddingR","align","pbaAlignLookup","reVAlign","reColSpan","reRowSpan","pbaVAlignLookup","v","<","=",">","<>","reApostrophe","reArrow","reClosingDQuote","reClosingSQuote","reCopyright","reDimsign","reDoublePrime","reEllipsis","reEmdash","reEndash","reOpenDQuote","reOpenSQuote","reRegistered","reSinglePrime","reTrademark","attr_class","attr_style","attr_lang","attr_align","attr_pad","listPad","reList","stack","currIndex","lastIndex","_lst","itemIndex","listAttr","reItem","item","destLevel","type","substr","newLi","lst","isFinite","parseInt","att","pop","start","apply","reDeflist","deflist","terms","def","parseColgroup","colgroup","isCol","span","width","reTable","rowgroups","caption","tAttr","tCurr","row","more","setRowGroup","reHead","summary","reCaption","reColgroup","reRowgroup","charToTag","reRow","th","cell","mx","table","tbody"],"mappings":"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","file":"textile.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"textile\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"textile\"] = factory();\n\telse\n\t\troot[\"textile\"] = factory();\n})(this, function() {\nreturn \n\n\n/** WEBPACK FOOTER **\n ** webpack/universalModuleDefinition\n **/","(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"textile\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"textile\"] = factory();\n\telse\n\t\troot[\"textile\"] = factory();\n})(this, function() {\nreturn /******/ (function(modules) { // webpackBootstrap\n/******/ \t// The module cache\n/******/ \tvar installedModules = {};\n/******/\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(installedModules[moduleId])\n/******/ \t\t\treturn installedModules[moduleId].exports;\n/******/\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = installedModules[moduleId] = {\n/******/ \t\t\texports: {},\n/******/ \t\t\tid: moduleId,\n/******/ \t\t\tloaded: false\n/******/ \t\t};\n/******/\n/******/ \t\t// Execute the module function\n/******/ \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n/******/\n/******/ \t\t// Flag the module as loaded\n/******/ \t\tmodule.loaded = true;\n/******/\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/\n/******/\n/******/ \t// expose the modules object (__webpack_modules__)\n/******/ \t__webpack_require__.m = modules;\n/******/\n/******/ \t// expose the module cache\n/******/ \t__webpack_require__.c = installedModules;\n/******/\n/******/ \t// __webpack_public_path__\n/******/ \t__webpack_require__.p = \"\";\n/******/\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(0);\n/******/ })\n/************************************************************************/\n/******/ ([\n/* 0 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/*\n\t** Textile parser for JavaScript\n\t**\n\t** Copyright (c) 2012 Borgar Þorsteinsson (MIT License).\n\t**\n\t*/\n\t\n\tvar merge = __webpack_require__(1);\n\t\n\tvar _require = __webpack_require__(2);\n\t\n\tvar toHTML = _require.toHTML;\n\t\n\tvar _require2 = __webpack_require__(6);\n\t\n\tvar parseFlow = _require2.parseFlow;\n\t\n\tvar _require3 = __webpack_require__(3);\n\t\n\tvar parseHtml = _require3.parseHtml;\n\t\n\t\n\tfunction textile(txt, opt) {\n\t // get a throw-away copy of options\n\t opt = merge(merge({}, textile.defaults), opt || {});\n\t // run the converter\n\t return parseFlow(txt, opt).map(toHTML).join('');\n\t};\n\tmodule.exports = textile;\n\t\n\t// options\n\ttextile.defaults = {\n\t // single-line linebreaks are converted to
    by default\n\t 'breaks': true\n\t};\n\ttextile.setOptions = textile.setoptions = function (opt) {\n\t merge(textile.defaults, opt);\n\t return this;\n\t};\n\t\n\ttextile.parse = textile.convert = textile;\n\ttextile.html_parser = parseHtml;\n\t\n\ttextile.jsonml = function (txt, opt) {\n\t // get a throw-away copy of options\n\t opt = merge(merge({}, textile.defaults), opt || {});\n\t // parse and return tree\n\t return ['html'].concat(parseFlow(txt, opt));\n\t};\n\ttextile.serialize = toHTML;\n\n/***/ },\n/* 1 */\n/***/ function(module, exports) {\n\n\t\"use strict\";\n\t\n\t// merge object b properties into object a\n\tmodule.exports = function merge(a, b) {\n\t if (b) {\n\t for (var k in b) {\n\t a[k] = b[k];\n\t }\n\t }\n\t return a;\n\t};\n\n/***/ },\n/* 2 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol ? \"symbol\" : typeof obj; };\n\t\n\t/*\n\t** JSONML helper methods - http://www.jsonml.org/\n\t**\n\t** This provides the `JSONML` object, which contains helper\n\t** methods for rendering JSONML to HTML.\n\t**\n\t** Note that the tag ! is taken to mean comment, this is however\n\t** not specified in the JSONML spec.\n\t*/\n\t\n\tvar singletons = __webpack_require__(3).singletons;\n\t\n\t// drop or add tab levels to JsonML tree\n\tfunction reIndent(ml, shiftBy) {\n\t // a bit obsessive, but there we are...\n\t if (!shiftBy) {\n\t return ml;\n\t }\n\t return ml.map(function (s) {\n\t if (/^\\n\\t+/.test(s)) {\n\t if (shiftBy < 0) {\n\t s = s.slice(0, shiftBy);\n\t } else {\n\t for (var i = 0; i < shiftBy; i++) {\n\t s += '\\t';\n\t }\n\t }\n\t } else if (Array.isArray(s)) {\n\t return reIndent(s, shiftBy);\n\t }\n\t return s;\n\t });\n\t}\n\t\n\tfunction escape(text, escapeQuotes) {\n\t return text.replace(/&(?!(#\\d{2,}|#x[\\da-fA-F]{2,}|[a-zA-Z][a-zA-Z1-4]{1,6});)/g, '&').replace(//g, '>').replace(/\"/g, escapeQuotes ? '"' : '\"').replace(/'/g, escapeQuotes ? ''' : \"'\");\n\t}\n\t\n\tfunction toHTML(jsonml) {\n\t jsonml = jsonml.concat();\n\t\n\t // basic case\n\t if (typeof jsonml === 'string') {\n\t return escape(jsonml);\n\t }\n\t\n\t var tag = jsonml.shift();\n\t var attributes = {};\n\t var tagAttrs = '';\n\t var content = [];\n\t\n\t if (jsonml.length && _typeof(jsonml[0]) === 'object' && !Array.isArray(jsonml[0])) {\n\t attributes = jsonml.shift();\n\t }\n\t\n\t while (jsonml.length) {\n\t content.push(toHTML(jsonml.shift()));\n\t }\n\t\n\t for (var a in attributes) {\n\t tagAttrs += attributes[a] == null ? ' ' + a : ' ' + a + '=\"' + escape(String(attributes[a]), true) + '\"';\n\t }\n\t\n\t // be careful about adding whitespace here for inline elements\n\t if (tag === '!') {\n\t return '';\n\t } else if (tag in singletons) {\n\t return '<' + tag + tagAttrs + ' />';\n\t } else {\n\t return '<' + tag + tagAttrs + '>' + content.join('') + '';\n\t }\n\t}\n\t\n\tmodule.exports = {\n\t reIndent: reIndent,\n\t toHTML: toHTML,\n\t escape: escape\n\t};\n\n/***/ },\n/* 3 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\tvar re = __webpack_require__(4);\n\tvar ribbon = __webpack_require__(5);\n\t\n\tre.pattern.html_id = '[a-zA-Z][a-zA-Z\\\\d:]*';\n\tre.pattern.html_attr = '(?:\"[^\"]+\"|\\'[^\\']+\\'|[^>\\\\s]+)';\n\t\n\tvar reAttr = re.compile(/^\\s*([^=\\s]+)(?:\\s*=\\s*(\"[^\"]+\"|'[^']+'|[^>\\s]+))?/);\n\tvar reComment = re.compile(/^/, 's');\n\tvar reEndTag = re.compile(/^<\\/([:html_id:])([^>]*)>/);\n\tvar reTag = re.compile(/^<([:html_id:])((?:\\s[^=\\s\\/]+(?:\\s*=\\s*[:html_attr:])?)+)?\\s*(\\/?)>(\\n*)/);\n\tvar reHtmlTagBlock = re.compile(/^\\s*<([:html_id:](?::[a-zA-Z\\d]+)*)((?:\\s[^=\\s\\/]+(?:\\s*=\\s*[:html_attr:])?)+)?\\s*(\\/?)>(\\n*)/);\n\t\n\t// area, base, basefont, bgsound, br, col, command, embed, frame, hr,\n\t// img, input, keygen, link, meta, param, source, track or wbr\n\tvar singletons = {\n\t br: 1,\n\t hr: 1,\n\t img: 1,\n\t link: 1,\n\t meta: 1,\n\t wbr: 1,\n\t area: 1,\n\t param: 1,\n\t input: 1,\n\t option: 1,\n\t base: 1,\n\t col: 1\n\t};\n\t\n\tfunction allowAll() {\n\t return true;\n\t}\n\t\n\tfunction testComment(src) {\n\t return reComment.exec(src);\n\t}\n\t\n\tfunction testOpenTagBlock(src) {\n\t return reHtmlTagBlock.exec(src);\n\t}\n\t\n\tfunction testOpenTag(src) {\n\t return reTag.exec(src);\n\t}\n\t\n\tfunction testCloseTag(src) {\n\t return reEndTag.exec(src);\n\t}\n\t\n\tfunction parseHtmlAttr(attrSrc) {\n\t // parse ATTR and add to element\n\t var attr = {};\n\t var m = void 0;\n\t while (m = reAttr.exec(attrSrc)) {\n\t attr[m[1]] = typeof m[2] === 'string' ? m[2].replace(/^([\"'])(.*)\\1$/, '$2') : null;\n\t attrSrc = attrSrc.slice(m[0].length);\n\t }\n\t return attr;\n\t}\n\t\n\t// This \"indesciminately\" parses HTML text into a list of JSON-ML element\n\t// No steps are taken however to prevent things like

    - user can still create nonsensical but \"well-formed\" markup\n\tfunction parseHtml(src, whitelistTags) {\n\t var root = [];\n\t var list = root;\n\t var _stack = [];\n\t var oktag = whitelistTags ? function (tag) {\n\t return tag in whitelistTags;\n\t } : allowAll;\n\t var m = void 0;\n\t var tag = void 0;\n\t\n\t src = typeof src === 'string' ? ribbon(src) : src;\n\t // loop\n\t do {\n\t // comment\n\t if ((m = testComment(src)) && oktag('!')) {\n\t src.advance(m[0]);\n\t list.push(['!', m[1]]);\n\t }\n\t\n\t // end tag\n\t else if ((m = testCloseTag(src)) && oktag(m[1])) {\n\t tag = m[1];\n\t if (_stack.length) {\n\t for (var i = _stack.length - 1; i >= 0; i--) {\n\t var head = _stack[i];\n\t if (head[0] === tag) {\n\t _stack.splice(i);\n\t list = _stack[_stack.length - 1] || root;\n\t break;\n\t }\n\t }\n\t }\n\t src.advance(m[0]);\n\t }\n\t\n\t // open/void tag\n\t else if ((m = testOpenTag(src)) && oktag(m[1])) {\n\t src.advance(m[0]);\n\t tag = m[1];\n\t var single = m[3] || m[1] in singletons;\n\t var tail = m[4];\n\t var element = [tag];\n\t\n\t // attributes\n\t if (m[2]) {\n\t element.push(parseHtmlAttr(m[2]));\n\t }\n\t\n\t // single tag\n\t if (single) {\n\t // let us add the element and continue our quest...\n\t list.push(element);\n\t if (tail) {\n\t list.push(tail);\n\t }\n\t }\n\t // open tag\n\t else {\n\t if (tail) {\n\t element.push(tail);\n\t }\n\t\n\t // TODO: some things auto close other things: ,
  • ,

    , \n\t // if ( tag === 'p' && _stack.length ) {\n\t // var seek = /^(p)$/;\n\t // for (var i=_stack.length-1; i>=0; i--) {\n\t // var head = _stack[i];\n\t // if ( seek.test( head[0] ) /* === tag */ ) {\n\t // //src.advance( m[0] );\n\t // _stack.splice( i );\n\t // list = _stack[i] || root;\n\t // }\n\t // }\n\t // }\n\t\n\t // TODO: some elements can move parser into \"text\" mode\n\t // style, xmp, iframe, noembed, noframe, textarea, title, script, noscript, plaintext\n\t // if ( /^(script)$/.test( tag ) ) { }\n\t\n\t _stack.push(element);\n\t list.push(element);\n\t list = element;\n\t }\n\t }\n\t // text content\n\t else {\n\t // no match, move by all \"uninteresting\" chars\n\t m = /([^<]+|[^\\0])/.exec(src);\n\t if (m) {\n\t list.push(m[0]);\n\t }\n\t src.advance(m ? m[0].length || 1 : 1);\n\t }\n\t } while (src.valueOf());\n\t\n\t return root;\n\t}\n\t\n\tmodule.exports = {\n\t singletons: singletons,\n\t parseHtml: parseHtml,\n\t parseHtmlAttr: parseHtmlAttr,\n\t testCloseTag: testCloseTag,\n\t testOpenTagBlock: testOpenTagBlock,\n\t testOpenTag: testOpenTag,\n\t testComment: testComment\n\t};\n\n/***/ },\n/* 4 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/*\n\t** Regular Expression helper methods\n\t**\n\t** This provides the `re` object, which contains several helper\n\t** methods for working with big regular expressions (soup).\n\t**\n\t*/\n\t\n\tvar _cache = {};\n\t\n\tvar re = module.exports = {\n\t\n\t pattern: {\n\t 'punct': '[!-/:-@\\\\[\\\\\\\\\\\\]-`{-~]',\n\t 'space': '\\\\s'\n\t },\n\t\n\t escape: function escape(src) {\n\t return src.replace(/[\\-\\[\\]\\{\\}\\(\\)\\*\\+\\?\\.,\\\\\\^\\$\\|#\\s]/g, '\\\\$&');\n\t },\n\t\n\t collapse: function collapse(src) {\n\t return src.replace(/(?:#.*?(?:\\n|$))/g, '').replace(/\\s+/g, '');\n\t },\n\t\n\t expandPatterns: function expandPatterns(src) {\n\t // TODO: provide escape for patterns: \\[:pattern:] ?\n\t return src.replace(/\\[:\\s*(\\w+)\\s*:\\]/g, function (m, k) {\n\t var ex = re.pattern[k];\n\t if (ex) {\n\t return re.expandPatterns(ex);\n\t } else {\n\t throw new Error('Pattern ' + m + ' not found in ' + src);\n\t }\n\t });\n\t },\n\t\n\t isRegExp: function isRegExp(r) {\n\t return Object.prototype.toString.call(r) === '[object RegExp]';\n\t },\n\t\n\t compile: function compile(src, flags) {\n\t if (re.isRegExp(src)) {\n\t if (arguments.length === 1) {\n\t // no flags arg provided, use the RegExp one\n\t flags = (src.global ? 'g' : '') + (src.ignoreCase ? 'i' : '') + (src.multiline ? 'm' : '');\n\t }\n\t src = src.source;\n\t }\n\t // don't do the same thing twice\n\t var ckey = src + (flags || '');\n\t if (ckey in _cache) {\n\t return _cache[ckey];\n\t }\n\t // allow classes\n\t var rx = re.expandPatterns(src);\n\t // allow verbose expressions\n\t if (flags && /x/.test(flags)) {\n\t rx = re.collapse(rx);\n\t }\n\t // allow dotall expressions\n\t if (flags && /s/.test(flags)) {\n\t rx = rx.replace(/([^\\\\])\\./g, '$1[^\\\\0]');\n\t }\n\t // TODO: test if MSIE and add replace \\s with [\\s\\u00a0] if it is?\n\t // clean flags and output new regexp\n\t flags = (flags || '').replace(/[^gim]/g, '');\n\t return _cache[ckey] = new RegExp(rx, flags);\n\t }\n\t\n\t};\n\n/***/ },\n/* 5 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\tmodule.exports = function ribbon(feed) {\n\t var org = String(feed);\n\t var slot = null;\n\t var pos = 0;\n\t\n\t return {\n\t\n\t save: function save() {\n\t slot = pos;\n\t },\n\t\n\t load: function load() {\n\t pos = slot;\n\t feed = org.slice(pos);\n\t this.$ = feed;\n\t },\n\t\n\t advance: function advance(n) {\n\t pos += typeof n === 'string' ? n.length : n;\n\t feed = org.slice(pos);\n\t this.$ = feed;\n\t return feed;\n\t },\n\t\n\t lookbehind: function lookbehind(nchars) {\n\t nchars = nchars == null ? 1 : nchars;\n\t return org.slice(pos - nchars, pos);\n\t },\n\t\n\t startsWith: function startsWith(s) {\n\t return feed.substring(0, s.length) === s;\n\t },\n\t\n\t valueOf: function valueOf() {\n\t this.$ = feed;\n\t return feed;\n\t },\n\t\n\t toString: function toString() {\n\t this.$ = feed;\n\t return feed;\n\t }\n\t\n\t };\n\t};\n\n/***/ },\n/* 6 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/*\n\t** textile flow content parser\n\t*/\n\tvar builder = __webpack_require__(7);\n\tvar ribbon = __webpack_require__(5);\n\tvar re = __webpack_require__(4);\n\tvar fixLinks = __webpack_require__(8);\n\t\n\tvar _require = __webpack_require__(3);\n\t\n\tvar parseHtml = _require.parseHtml;\n\tvar parseHtmlAttr = _require.parseHtmlAttr;\n\tvar singletons = _require.singletons;\n\tvar testComment = _require.testComment;\n\tvar testOpenTagBlock = _require.testOpenTagBlock;\n\t\n\tvar _require2 = __webpack_require__(9);\n\t\n\tvar parsePhrase = _require2.parsePhrase;\n\t\n\tvar _require3 = __webpack_require__(10);\n\t\n\tvar copyAttr = _require3.copyAttr;\n\tvar parseAttr = _require3.parseAttr;\n\t\n\tvar _require4 = __webpack_require__(13);\n\t\n\tvar testList = _require4.testList;\n\tvar parseList = _require4.parseList;\n\t\n\tvar _require5 = __webpack_require__(14);\n\t\n\tvar testDefList = _require5.testDefList;\n\tvar parseDefList = _require5.parseDefList;\n\t\n\tvar _require6 = __webpack_require__(15);\n\t\n\tvar testTable = _require6.testTable;\n\tvar parseTable = _require6.parseTable;\n\t\n\tvar _require7 = __webpack_require__(12);\n\t\n\tvar txblocks = _require7.txblocks;\n\tvar txlisthd = _require7.txlisthd;\n\tvar txattr = _require7.txattr;\n\t\n\tre.pattern.txblocks = txblocks;\n\tre.pattern.txlisthd = txlisthd;\n\tre.pattern.txattr = txattr;\n\t\n\t// HTML tags allowed in the document (root) level that trigger HTML parsing\n\tvar allowedBlocktags = {\n\t 'p': 0,\n\t 'hr': 0,\n\t 'ul': 1,\n\t 'ol': 0,\n\t 'li': 0,\n\t 'div': 1,\n\t 'pre': 0,\n\t 'object': 1,\n\t 'script': 0,\n\t 'noscript': 0,\n\t 'blockquote': 1,\n\t 'notextile': 1\n\t};\n\t\n\tvar reBlock = re.compile(/^([:txblocks:])/);\n\t// const reBlockSE = re.compile( /^[:txblocks:]$/ );\n\tvar reBlockNormal = re.compile(/^(.*?)($|\\r?\\n(?=[:txlisthd:])|\\r?\\n(?:\\s*\\n|$)+)/, 's');\n\tvar reBlockExtended = re.compile(/^(.*?)($|\\r?\\n(?=[:txlisthd:])|\\r?\\n+(?=[:txblocks:][:txattr:]\\.))/, 's');\n\tvar reRuler = /^(\\-\\-\\-+|\\*\\*\\*+|___+)(\\r?\\n\\s+|$)/;\n\tvar reLinkRef = re.compile(/^\\[([^\\]]+)\\]((?:https?:\\/\\/|\\/)\\S+)(?:\\s*\\n|$)/);\n\tvar reFootnoteDef = /^fn\\d+$/;\n\t\n\tfunction paragraph(s, tag, pba, linebreak, options) {\n\t tag = tag || 'p';\n\t var out = [];\n\t s.split(/(?:\\r?\\n){2,}/).forEach(function (bit, i) {\n\t if (tag === 'p' && /^\\s/.test(bit)) {\n\t // no-paragraphs\n\t // WTF?: Why does Textile not allow linebreaks in spaced lines\n\t bit = bit.replace(/\\r?\\n[\\t ]/g, ' ').trim();\n\t out = out.concat(parsePhrase(bit, options));\n\t } else {\n\t if (linebreak && i) {\n\t out.push(linebreak);\n\t }\n\t out.push(pba ? [tag, pba].concat(parsePhrase(bit, options)) : [tag].concat(parsePhrase(bit, options)));\n\t }\n\t });\n\t return out;\n\t};\n\t\n\tfunction parseFlow(src, options) {\n\t var list = builder();\n\t\n\t var linkRefs = void 0;\n\t var m = void 0;\n\t\n\t src = ribbon(src.replace(/^( *\\r?\\n)+/, ''));\n\t\n\t // loop\n\t while (src.valueOf()) {\n\t src.save();\n\t\n\t // link_ref -- this goes first because it shouldn't trigger a linebreak\n\t if (m = reLinkRef.exec(src)) {\n\t if (!linkRefs) {\n\t linkRefs = {};\n\t }\n\t src.advance(m[0]);\n\t linkRefs[m[1]] = m[2];\n\t continue;\n\t }\n\t\n\t // add linebreak\n\t list.linebreak();\n\t\n\t // named block\n\t if (m = reBlock.exec(src)) {\n\t src.advance(m[0]);\n\t var blockType = m[0];\n\t var pba = parseAttr(src, blockType);\n\t\n\t if (pba) {\n\t src.advance(pba[0]);\n\t pba = pba[1];\n\t }\n\t if (m = /^\\.(\\.?)(?:\\s|(?=:))/.exec(src)) {\n\t // FIXME: this whole copyAttr seems rather strange?\n\t // slurp rest of block\n\t var extended = !!m[1];\n\t var reBlockGlob = extended ? reBlockExtended : reBlockNormal;\n\t m = reBlockGlob.exec(src.advance(m[0]));\n\t src.advance(m[0]);\n\t // bq | bc | notextile | pre | h# | fn# | p | ###\n\t if (blockType === 'bq') {\n\t var inner = m[1];\n\t if (m = /^:(\\S+)\\s+/.exec(inner)) {\n\t if (!pba) {\n\t pba = {};\n\t }\n\t pba.cite = m[1];\n\t inner = inner.slice(m[0].length);\n\t }\n\t // RedCloth adds all attr to both: this is bad because it produces duplicate IDs\n\t var par = paragraph(inner, 'p', copyAttr(pba, { 'cite': 1, 'id': 1 }), '\\n', options);\n\t list.add(['blockquote', pba, '\\n'].concat(par).concat(['\\n']));\n\t // FIXME: looks like .linebreak can work here\n\t } else if (blockType === 'bc') {\n\t var subPba = pba ? copyAttr(pba, { 'id': 1 }) : null;\n\t list.add(['pre', pba, subPba ? ['code', subPba, m[1]] : ['code', m[1]]]);\n\t } else if (blockType === 'notextile') {\n\t list.merge(parseHtml(m[1]));\n\t } else if (blockType === '###') {\n\t // ignore the insides\n\t } else if (blockType === 'pre') {\n\t // I disagree with RedCloth, but agree with PHP here:\n\t // \"pre(foo#bar).. line1\\n\\nline2\" prevents multiline preformat blocks\n\t // ...which seems like the whole point of having an extended pre block?\n\t list.add(['pre', pba, m[1]]);\n\t } else if (reFootnoteDef.test(blockType)) {\n\t // footnote\n\t // Need to be careful: RedCloth fails \"fn1(foo#m). footnote\" -- it confuses the ID\n\t var fnid = blockType.replace(/\\D+/g, '');\n\t if (!pba) {\n\t pba = {};\n\t }\n\t pba.class = (pba['class'] ? pba['class'] + ' ' : '') + 'footnote';\n\t pba.id = 'fn' + fnid;\n\t list.add(['p', pba, ['a', { 'href': '#fnr' + fnid }, ['sup', fnid]], ' '].concat(parsePhrase(m[1], options)));\n\t } else {\n\t // heading | paragraph\n\t list.merge(paragraph(m[1], blockType, pba, '\\n', options));\n\t }\n\t continue;\n\t } else {\n\t src.load();\n\t }\n\t }\n\t\n\t // HTML comment\n\t if (m = testComment(src)) {\n\t src.advance(m[0] + (/(?:\\s*\\n+)+/.exec(src) || [])[0]);\n\t list.add(['!', m[1]]);\n\t continue;\n\t }\n\t\n\t // block HTML\n\t if (m = testOpenTagBlock(src)) {\n\t var tag = m[1];\n\t var single = m[3] || tag in singletons;\n\t var tail = m[4];\n\t\n\t // Unsurprisingly, all Textile implementations I have tested have trouble parsing simple HTML:\n\t //\n\t // \"
    a\\n
    b\\n
    c\\n
    d\"\n\t //\n\t // I simply match them here as there is no way anyone is using nested HTML today, or if they\n\t // are, then this will at least output less broken HTML as redundant tags will get quoted.\n\t\n\t // Is block tag? ...\n\t if (tag in allowedBlocktags) {\n\t src.advance(m[0]);\n\t\n\t var element = [tag];\n\t\n\t if (m[2]) {\n\t element.push(parseHtmlAttr(m[2]));\n\t }\n\t\n\t // single tag\n\t if (single) {\n\t // let us add the element and continue our quest...\n\t list.add(element);\n\t continue;\n\t }\n\t // block\n\t else {\n\t // gulp up the rest of this block...\n\t var reEndTag = re.compile('^(.*?)(\\\\s*)()(\\\\s*)', 's');\n\t if (m = reEndTag.exec(src)) {\n\t src.advance(m[0]);\n\t if (tag === 'pre') {\n\t element.push(tail);\n\t element = element.concat(parseHtml(m[1].replace(/(\\r?\\n)+$/, ''), { 'code': 1 }));\n\t if (m[2]) {\n\t element.push(m[2]);\n\t }\n\t list.add(element);\n\t } else if (tag === 'notextile') {\n\t element = parseHtml(m[1].trim());\n\t list.merge(element);\n\t } else if (tag === 'script' || tag === 'noscript') {\n\t element.push(tail + m[1]);\n\t list.add(element);\n\t } else {\n\t // These strange (and unnecessary) linebreak tests are here to get the\n\t // tests working perfectly. In reality, this doesn't matter one bit.\n\t if (/\\n/.test(tail)) {\n\t element.push('\\n');\n\t }\n\t if (/\\n/.test(m[1])) {\n\t element = element.concat(parseFlow(m[1], options));\n\t } else {\n\t element = element.concat(parsePhrase(m[1].replace(/^ +/, ''), options));\n\t }\n\t if (/\\n/.test(m[2])) {\n\t element.push('\\n');\n\t }\n\t\n\t list.add(element);\n\t }\n\t continue;\n\t }\n\t }\n\t }\n\t src.load();\n\t }\n\t\n\t // ruler\n\t if (m = reRuler.exec(src)) {\n\t src.advance(m[0]);\n\t list.add(['hr']);\n\t continue;\n\t }\n\t\n\t // list\n\t if (m = testList(src)) {\n\t src.advance(m[0]);\n\t list.add(parseList(m[0], options));\n\t continue;\n\t }\n\t\n\t // definition list\n\t if (m = testDefList(src)) {\n\t src.advance(m[0]);\n\t list.add(parseDefList(m[0], options));\n\t continue;\n\t }\n\t\n\t // table\n\t if (m = testTable(src)) {\n\t src.advance(m[0]);\n\t list.add(parseTable(m[1], options));\n\t continue;\n\t }\n\t\n\t // paragraph\n\t m = reBlockNormal.exec(src);\n\t list.merge(paragraph(m[1], 'p', undefined, '\\n', options));\n\t src.advance(m[0]);\n\t }\n\t\n\t return linkRefs ? fixLinks(list.get(), linkRefs) : list.get();\n\t}\n\t\n\texports.parseFlow = parseFlow;\n\n/***/ },\n/* 7 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\tmodule.exports = function builder(initArr) {\n\t var arr = Array.isArray(initArr) ? initArr : [];\n\t\n\t return {\n\t add: function add(node) {\n\t if (typeof node === 'string' && typeof arr[arr.length - 1] === 'string') {\n\t // join if possible\n\t arr[arr.length - 1] += node;\n\t } else if (Array.isArray(node)) {\n\t arr.push(node.filter(function (s) {\n\t return s !== undefined;\n\t }));\n\t } else if (node) {\n\t arr.push(node);\n\t }\n\t return this;\n\t },\n\t\n\t merge: function merge(arr) {\n\t for (var i = 0, l = arr.length; i < l; i++) {\n\t this.add(arr[i]);\n\t }\n\t return this;\n\t },\n\t\n\t linebreak: function linebreak() {\n\t if (arr.length) {\n\t this.add('\\n');\n\t }\n\t },\n\t\n\t get: function get() {\n\t return arr;\n\t }\n\t };\n\t};\n\n/***/ },\n/* 8 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\tvar _typeof = typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol ? \"symbol\" : typeof obj; };\n\t\n\t// recurse the tree and swap out any \"href\" attributes\n\t// this uses the context as the replace dictionary so it can be fed to Array#map\n\tmodule.exports = function fixLinks(ml, dict) {\n\t if (Array.isArray(ml)) {\n\t if (ml[0] === 'a') {\n\t // found a link\n\t var attr = ml[1];\n\t if ((typeof attr === 'undefined' ? 'undefined' : _typeof(attr)) === 'object' && 'href' in attr && attr.href in dict) {\n\t attr.href = dict[attr.href];\n\t }\n\t }\n\t for (var i = 0, l = ml.length; i < l; i++) {\n\t if (Array.isArray(ml[i])) {\n\t fixLinks(ml[i], dict);\n\t }\n\t }\n\t }\n\t return ml;\n\t};\n\n/***/ },\n/* 9 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/* textile inline parser */\n\t\n\tvar ribbon = __webpack_require__(5);\n\tvar builder = __webpack_require__(7);\n\tvar re = __webpack_require__(4);\n\t\n\tvar _require = __webpack_require__(10);\n\t\n\tvar parseAttr = _require.parseAttr;\n\t\n\tvar _require2 = __webpack_require__(11);\n\t\n\tvar parseGlyph = _require2.parseGlyph;\n\t\n\tvar _require3 = __webpack_require__(3);\n\t\n\tvar parseHtmlAttr = _require3.parseHtmlAttr;\n\tvar singletons = _require3.singletons;\n\tvar testComment = _require3.testComment;\n\tvar testOpenTag = _require3.testOpenTag;\n\t\n\tvar _require4 = __webpack_require__(12);\n\t\n\tvar ucaps = _require4.ucaps;\n\tvar txattr = _require4.txattr;\n\tvar txcite = _require4.txcite;\n\t\n\tre.pattern.txattr = txattr;\n\tre.pattern.txcite = txcite;\n\tre.pattern.ucaps = ucaps;\n\t\n\tvar phraseConvert = {\n\t '*': 'strong',\n\t '**': 'b',\n\t '??': 'cite',\n\t '_': 'em',\n\t '__': 'i',\n\t '-': 'del',\n\t '%': 'span',\n\t '+': 'ins',\n\t '~': 'sub',\n\t '^': 'sup',\n\t '@': 'code'\n\t};\n\t\n\tvar rePhrase = /^([\\[\\{]?)(__?|\\*\\*?|\\?\\?|[\\-\\+\\^~@%])/;\n\tvar reImage = re.compile(/^!(?!\\s)([:txattr:](?:\\.[^\\n\\S]|\\.(?:[^\\.\\/]))?)([^!\\s]+?) ?(?:\\(((?:[^\\(\\)]+|\\([^\\(\\)]+\\))+)\\))?!(?::([^\\s]+?(?=[!-\\.:-@\\[\\\\\\]-`{-~](?:$|\\s)|\\s|$)))?/);\n\tvar reImageFenced = re.compile(/^\\[!(?!\\s)([:txattr:](?:\\.[^\\n\\S]|\\.(?:[^\\.\\/]))?)([^!\\s]+?) ?(?:\\(((?:[^\\(\\)]+|\\([^\\(\\)]+\\))+)\\))?!(?::([^\\s]+?(?=[!-\\.:-@\\[\\\\\\]-`{-~](?:$|\\s)|\\s|$)))?\\]/);\n\t// NB: there is an exception in here to prevent matching \"TM)\"\n\tvar reCaps = re.compile(/^((?!TM\\)|tm\\))[[:ucaps:]](?:[[:ucaps:]\\d]{1,}(?=\\()|[[:ucaps:]\\d]{2,}))(?:\\((.*?)\\))?(?=\\W|$)/);\n\tvar reLink = re.compile(/^\"(?!\\s)((?:[^\\n\"]|\"(?![\\s:])[^\\n\"]+\"(?!:))+)\"[:txcite:]/);\n\tvar reLinkFenced = /^\\[\"([^\\n]+?)\":((?:\\[[a-z0-9]*\\]|[^\\]])+)\\]/;\n\tvar reLinkTitle = /\\s*\\(((?:\\([^\\(\\)]*\\)|[^\\(\\)])+)\\)$/;\n\tvar reFootnote = /^\\[(\\d+)(!?)\\]/;\n\t\n\tfunction parsePhrase(src, options) {\n\t src = ribbon(src);\n\t\n\t var list = builder();\n\t var m = void 0;\n\t var pba = void 0;\n\t\n\t // loop\n\t do {\n\t src.save();\n\t\n\t // linebreak -- having this first keeps it from messing to much with other phrases\n\t if (src.startsWith('\\r\\n')) {\n\t src.advance(1); // skip cartridge returns\n\t }\n\t if (src.startsWith('\\n')) {\n\t src.advance(1);\n\t if (options.breaks) {\n\t list.add(['br']);\n\t }\n\t list.add('\\n');\n\t continue;\n\t }\n\t\n\t // inline notextile\n\t if (m = /^==(.*?)==/.exec(src)) {\n\t src.advance(m[0]);\n\t list.add(m[1]);\n\t continue;\n\t }\n\t\n\t // lookbehind => /([\\s>.,\"'?!;:])$/\n\t var behind = src.lookbehind(1);\n\t var boundary = !behind || /^[\\s>.,\"'?!;:()]$/.test(behind);\n\t // FIXME: need to test right boundary for phrases as well\n\t if ((m = rePhrase.exec(src)) && (boundary || m[1])) {\n\t src.advance(m[0]);\n\t var tok = m[2];\n\t var fence = m[1];\n\t var phraseType = phraseConvert[tok];\n\t var code = phraseType === 'code';\n\t\n\t if (pba = !code && parseAttr(src, phraseType, tok)) {\n\t src.advance(pba[0]);\n\t pba = pba[1];\n\t }\n\t // FIXME: if we can't match the fence on the end, we should output fence-prefix as normal text\n\t // seek end\n\t var mMid = void 0;\n\t var mEnd = void 0;\n\t if (fence === '[') {\n\t mMid = '^(.*?)';\n\t mEnd = '(?:])';\n\t } else if (fence === '{') {\n\t mMid = '^(.*?)';\n\t mEnd = '(?:})';\n\t } else {\n\t var t1 = re.escape(tok.charAt(0));\n\t mMid = code ? '^(\\\\S+|\\\\S+.*?\\\\S)' : '^([^\\\\s' + t1 + ']+|[^\\\\s' + t1 + '].*?\\\\S(' + t1 + '*))';\n\t mEnd = '(?=$|[\\\\s.,\"\\'!?;:()«»„“”‚‘’])';\n\t }\n\t var rx = re.compile(mMid + '(' + re.escape(tok) + ')' + mEnd);\n\t if ((m = rx.exec(src)) && m[1]) {\n\t src.advance(m[0]);\n\t if (code) {\n\t list.add([phraseType, m[1]]);\n\t } else {\n\t list.add([phraseType, pba].concat(parsePhrase(m[1], options)));\n\t }\n\t continue;\n\t }\n\t // else\n\t src.load();\n\t }\n\t\n\t // image\n\t if ((m = reImage.exec(src)) || (m = reImageFenced.exec(src))) {\n\t src.advance(m[0]);\n\t\n\t pba = m[1] && parseAttr(m[1], 'img');\n\t var attr = pba ? pba[1] : { 'src': '' };\n\t var img = ['img', attr];\n\t attr.src = m[2];\n\t attr.alt = m[3] ? attr.title = m[3] : '';\n\t\n\t if (m[4]) {\n\t // +cite causes image to be wraped with a link (or link_ref)?\n\t // TODO: support link_ref for image cite\n\t img = ['a', { 'href': m[4] }, img];\n\t }\n\t list.add(img);\n\t continue;\n\t }\n\t\n\t // html comment\n\t if (m = testComment(src)) {\n\t src.advance(m[0]);\n\t list.add(['!', m[1]]);\n\t continue;\n\t }\n\t // html tag\n\t // TODO: this seems to have a lot of overlap with block tags... DRY?\n\t if (m = testOpenTag(src)) {\n\t src.advance(m[0]);\n\t var tag = m[1];\n\t var single = m[3] || m[1] in singletons;\n\t var element = [tag];\n\t var tail = m[4];\n\t if (m[2]) {\n\t element.push(parseHtmlAttr(m[2]));\n\t }\n\t if (single) {\n\t // single tag\n\t list.add(element).add(tail);\n\t continue;\n\t } else {\n\t // need terminator\n\t // gulp up the rest of this block...\n\t var reEndTag = re.compile('^(.*?)()', 's');\n\t if (m = reEndTag.exec(src)) {\n\t src.advance(m[0]);\n\t if (tag === 'code') {\n\t element.push(tail, m[1]);\n\t } else if (tag === 'notextile') {\n\t list.merge(parsePhrase(m[1], options));\n\t continue;\n\t } else {\n\t element = element.concat(parsePhrase(m[1], options));\n\t }\n\t list.add(element);\n\t continue;\n\t }\n\t // end tag is missing, treat tag as normal text...\n\t }\n\t src.load();\n\t }\n\t\n\t // footnote\n\t if ((m = reFootnote.exec(src)) && /\\S/.test(behind)) {\n\t src.advance(m[0]);\n\t list.add(['sup', { 'class': 'footnote', 'id': 'fnr' + m[1] }, m[2] === '!' ? m[1] // \"!\" suppresses the link\n\t : ['a', { href: '#fn' + m[1] }, m[1]]]);\n\t continue;\n\t }\n\t\n\t // caps / abbr\n\t if (m = reCaps.exec(src)) {\n\t src.advance(m[0]);\n\t var caps = ['span', { 'class': 'caps' }, m[1]];\n\t if (m[2]) {\n\t // FIXME: use , not acronym!\n\t caps = ['acronym', { 'title': m[2] }, caps];\n\t }\n\t list.add(caps);\n\t continue;\n\t }\n\t\n\t // links\n\t if (boundary && (m = reLink.exec(src)) || (m = reLinkFenced.exec(src))) {\n\t src.advance(m[0]);\n\t var title = m[1].match(reLinkTitle);\n\t var inner = title ? m[1].slice(0, m[1].length - title[0].length) : m[1];\n\t if (pba = parseAttr(inner, 'a')) {\n\t inner = inner.slice(pba[0]);\n\t pba = pba[1];\n\t } else {\n\t pba = {};\n\t }\n\t if (title && !inner) {\n\t inner = title[0];\n\t title = '';\n\t }\n\t pba.href = m[2];\n\t if (title) {\n\t pba.title = title[1];\n\t }\n\t list.add(['a', pba].concat(parsePhrase(inner.replace(/^(\\.?\\s*)/, ''), options)));\n\t continue;\n\t }\n\t\n\t // no match, move by all \"uninteresting\" chars\n\t m = /([a-zA-Z0-9,.':]+|[ \\f\\r\\t\\v\\xA0\\u2028\\u2029]+|[^\\0])/.exec(src);\n\t if (m) {\n\t list.add(m[0]);\n\t }\n\t src.advance(m ? m[0].length || 1 : 1);\n\t } while (src.valueOf());\n\t\n\t return list.get().map(parseGlyph);\n\t}\n\t\n\texports.parsePhrase = parsePhrase;\n\n/***/ },\n/* 10 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\tvar reClassid = /^\\(([^\\(\\)\\n]+)\\)/;\n\tvar rePaddingL = /^(\\(+)/;\n\tvar rePaddingR = /^(\\)+)/;\n\tvar reAlignBlock = /^(<>|<|>|=)/;\n\tvar reAlignImg = /^(<|>|=)/;\n\tvar reVAlign = /^(~|\\^|\\-)/;\n\tvar reColSpan = /^\\\\(\\d+)/;\n\tvar reRowSpan = /^\\/(\\d+)/;\n\tvar reStyles = /^\\{([^\\}]*)\\}/;\n\tvar reCSS = /^\\s*([^:\\s]+)\\s*:\\s*(.+)\\s*$/;\n\tvar reLang = /^\\[([^\\[\\]\\n]+)\\]/;\n\t\n\tvar pbaAlignLookup = {\n\t '<': 'left',\n\t '=': 'center',\n\t '>': 'right',\n\t '<>': 'justify'\n\t};\n\t\n\tvar pbaVAlignLookup = {\n\t '~': 'bottom',\n\t '^': 'top',\n\t '-': 'middle'\n\t};\n\t\n\tfunction copyAttr(s, blacklist) {\n\t if (!s) {\n\t return undefined;\n\t }\n\t var d = {};\n\t for (var k in s) {\n\t if (k in s && (!blacklist || !(k in blacklist))) {\n\t d[k] = s[k];\n\t }\n\t }\n\t return d;\n\t}\n\t\n\tfunction testBlock(name) {\n\t // \"in\" test would be better but what about fn#.?\n\t return (/^(?:table|t[dh]|t(?:foot|head|body)|b[qc]|div|notextile|pre|h[1-6]|fn\\\\d+|p|###)$/.test(name)\n\t );\n\t}\n\t\n\t/*\n\t The attr bit causes massive problems for span elements when parentheses are used.\n\t Parentheses are a total mess and, unsurprisingly, cause trip-ups:\n\t\n\t RC: `_{display:block}(span) span (span)_` -> `(span) span (span)`\n\t PHP: `_{display:block}(span) span (span)_` -> `(span) span (span)`\n\t\n\t PHP and RC seem to mostly solve this by not parsing a final attr parens on spans if the\n\t following character is a non-space. I've duplicated that: Class/ID is not matched on spans\n\t if it is followed by `endToken` or .\n\t\n\t Lang is not matched here if it is followed by the end token. Theoretically I could limit the lang\n\t attribute to /^\\[[a-z]{2+}(\\-[a-zA-Z0-9]+)*\\]/ because Textile is layered on top of HTML which\n\t only accepts valid BCP 47 language tags, but who knows what atrocities are being preformed\n\t out there in the real world. So this attempts to emulate the other libraries.\n\t*/\n\tfunction parseAttr(input, element, endToken) {\n\t input = String(input);\n\t if (!input || element === 'notextile') {\n\t return undefined;\n\t }\n\t\n\t var m = void 0;\n\t var st = {};\n\t var o = { 'style': st };\n\t var remaining = input;\n\t\n\t var isBlock = testBlock(element);\n\t var isImg = element === 'img';\n\t var isList = element === 'li';\n\t var isPhrase = !isBlock && !isImg && element !== 'a';\n\t var reAlign = isImg ? reAlignImg : reAlignBlock;\n\t\n\t do {\n\t if (m = reStyles.exec(remaining)) {\n\t m[1].split(';').forEach(function (p) {\n\t var d = p.match(reCSS);\n\t if (d) {\n\t st[d[1]] = d[2];\n\t }\n\t });\n\t remaining = remaining.slice(m[0].length);\n\t continue;\n\t }\n\t\n\t if (m = reLang.exec(remaining)) {\n\t var rm = remaining.slice(m[0].length);\n\t if (!rm && isPhrase || endToken && endToken === rm.slice(0, endToken.length)) {\n\t m = null;\n\t } else {\n\t o['lang'] = m[1];\n\t remaining = remaining.slice(m[0].length);\n\t }\n\t continue;\n\t }\n\t\n\t if (m = reClassid.exec(remaining)) {\n\t var _rm = remaining.slice(m[0].length);\n\t if (!_rm && isPhrase || endToken && (_rm[0] === ' ' || endToken === _rm.slice(0, endToken.length))) {\n\t m = null;\n\t } else {\n\t var bits = m[1].split('#');\n\t if (bits[0]) {\n\t o.class = bits[0];\n\t }\n\t if (bits[1]) {\n\t o.id = bits[1];\n\t }\n\t remaining = _rm;\n\t }\n\t continue;\n\t }\n\t\n\t if (isBlock || isList) {\n\t if (m = rePaddingL.exec(remaining)) {\n\t st['padding-left'] = m[1].length + 'em';\n\t remaining = remaining.slice(m[0].length);\n\t continue;\n\t }\n\t if (m = rePaddingR.exec(remaining)) {\n\t st['padding-right'] = m[1].length + 'em';\n\t remaining = remaining.slice(m[0].length);\n\t continue;\n\t }\n\t }\n\t\n\t // only for blocks:\n\t if (isImg || isBlock || isList) {\n\t if (m = reAlign.exec(remaining)) {\n\t var align = pbaAlignLookup[m[1]];\n\t if (isImg) {\n\t o['align'] = align;\n\t } else {\n\t st['text-align'] = align;\n\t }\n\t remaining = remaining.slice(m[0].length);\n\t continue;\n\t }\n\t }\n\t\n\t // only for table cells\n\t if (element === 'td' || element === 'tr') {\n\t if (m = reVAlign.exec(remaining)) {\n\t st['vertical-align'] = pbaVAlignLookup[m[1]];\n\t remaining = remaining.slice(m[0].length);\n\t continue;\n\t }\n\t }\n\t if (element === 'td') {\n\t if (m = reColSpan.exec(remaining)) {\n\t o['colspan'] = m[1];\n\t remaining = remaining.slice(m[0].length);\n\t continue;\n\t }\n\t if (m = reRowSpan.exec(remaining)) {\n\t o['rowspan'] = m[1];\n\t remaining = remaining.slice(m[0].length);\n\t continue;\n\t }\n\t }\n\t } while (m);\n\t\n\t // collapse styles\n\t var s = [];\n\t for (var v in st) {\n\t s.push(v + ':' + st[v]);\n\t }\n\t if (s.length) {\n\t o.style = s.join(';');\n\t } else {\n\t delete o.style;\n\t }\n\t\n\t return remaining === input ? undefined : [input.length - remaining.length, o];\n\t}\n\t\n\tmodule.exports = {\n\t copyAttr: copyAttr,\n\t parseAttr: parseAttr\n\t};\n\n/***/ },\n/* 11 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/* textile glyph parser */\n\t\n\tvar re = __webpack_require__(4);\n\t\n\tvar reApostrophe = /(\\w)'(\\w)/g;\n\tvar reArrow = /([^\\-]|^)->/;\n\tvar reClosingDQuote = re.compile(/([^\\s\\[\\(])\"(?=$|\\s|[:punct:])/g);\n\tvar reClosingSQuote = re.compile(/([^\\s\\[\\(])'(?=$|\\s|[:punct:])/g);\n\tvar reCopyright = /(\\b ?|\\s|^)(?:\\(C\\)|\\[C\\])/gi;\n\tvar reDimsign = /([\\d\\.,]+['\"]? ?)x( ?)(?=[\\d\\.,]['\"]?)/g;\n\tvar reDoublePrime = re.compile(/(\\d*[\\.,]?\\d+)\"(?=\\s|$|[:punct:])/g);\n\tvar reEllipsis = /([^.]?)\\.{3}/g;\n\tvar reEmdash = /(^|[\\s\\w])--([\\s\\w]|$)/g;\n\tvar reEndash = / - /g;\n\tvar reOpenDQuote = /\"/g;\n\tvar reOpenSQuote = /'/g;\n\tvar reRegistered = /(\\b ?|\\s|^)(?:\\(R\\)|\\[R\\])/gi;\n\tvar reSinglePrime = re.compile(/(\\d*[\\.,]?\\d+)'(?=\\s|$|[:punct:])/g);\n\tvar reTrademark = /(\\b ?|\\s|^)(?:\\((?:TM|tm)\\)|\\[(?:TM|tm)\\])/g;\n\t\n\texports.parseGlyph = function parseGlyph(src) {\n\t if (typeof src !== 'string') {\n\t return src;\n\t }\n\t // NB: order is important here ...\n\t return src.replace(reArrow, '$1→').replace(reDimsign, '$1×$2').replace(reEllipsis, '$1…').replace(reEmdash, '$1—$2').replace(reEndash, ' – ').replace(reTrademark, '$1™').replace(reRegistered, '$1®').replace(reCopyright, '$1©')\n\t // double quotes\n\t .replace(reDoublePrime, '$1″').replace(reClosingDQuote, '$1”').replace(reOpenDQuote, '“')\n\t // single quotes\n\t .replace(reSinglePrime, '$1′').replace(reApostrophe, '$1’$2').replace(reClosingSQuote, '$1’').replace(reOpenSQuote, '‘')\n\t // fractions and degrees\n\t .replace(/[\\(\\[]1\\/4[\\]\\)]/, '¼').replace(/[\\(\\[]1\\/2[\\]\\)]/, '½').replace(/[\\(\\[]3\\/4[\\]\\)]/, '¾').replace(/[\\(\\[]o[\\]\\)]/, '°').replace(/[\\(\\[]\\+\\/\\-[\\]\\)]/, '±');\n\t};\n\n/***/ },\n/* 12 */\n/***/ function(module, exports) {\n\n\t'use strict';\n\t\n\t/* eslint camelcase: 0 */\n\t\n\texports.txblocks = '(?:b[qc]|div|notextile|pre|h[1-6]|fn\\\\d+|p|###)';\n\t\n\texports.ucaps = 'A-Z' +\n\t// Latin extended À-Þ\n\t'À-ÖØ-Þ' +\n\t// Latin caps with embelishments and ligatures...\n\t'ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮİIJĴĶĹĻĽĿ' + 'ŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŸŹŻŽ' + 'ƁƂƄƆƇƉ-ƋƎ-ƑƓƔƖ-ƘƜƝƟƠƢƤƦƧƩƬƮƯƱ-ƳƵƷƸƼ' + 'DŽLJNJǍǏǑǓǕǗǙǛǞǠǢǤǦǨǪǬǮDZǴǶ-ǸǺǼǾ' + 'ȀȂȄȆȈȊȌȎȐȒȔȖȘȚȜȞȠȢȤȦȨȪȬȮȰȲȺȻȽȾ' + 'ɁɃ-ɆɈɊɌɎ' + 'ḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀ' + 'ṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾ' + 'ẀẂẄẆẈẊẌẎẐẒẔẞẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾ' + 'ỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸỺỼỾ' + 'ⱠⱢ-ⱤⱧⱩⱫⱭ-ⱰⱲⱵⱾⱿ' + 'ꜢꜤꜦꜨꜪꜬꜮꜲꜴꜶꜸꜺꜼꜾ' + 'ꝀꝂꝄꝆꝈꝊꝌꝎꝐꝒꝔꝖꝘꝚꝜꝞꝠꝢꝤꝦꝨꝪꝬꝮꝹꝻꝽꝾ' + 'ꞀꞂꞄꞆꞋꞍꞐꞒꞠꞢꞤꞦꞨꞪ';\n\t\n\texports.txcite = ':((?:[^\\\\s()]|\\\\([^\\\\s()]+\\\\)|[()])+?)(?=[!-\\\\.:-@\\\\[\\\\\\\\\\\\]-`{-~]+(?:$|\\\\s)|$|\\\\s)';\n\t\n\tvar attr_class = exports.attr_class = '\\\\([^\\\\)]+\\\\)';\n\tvar attr_style = exports.attr_style = '\\\\{[^\\\\}]+\\\\}';\n\tvar attr_lang = exports.attr_lang = '\\\\[[^\\\\[\\\\]]+\\\\]';\n\tvar attr_align = exports.attr_align = '(?:<>|<|>|=)';\n\tvar attr_pad = exports.attr_pad = '[\\\\(\\\\)]+';\n\t\n\tvar txattr = exports.txattr = '(?:' + attr_class + '|' + attr_style + '|' + attr_lang + '|' + attr_align + '|' + attr_pad + ')*';\n\t\n\texports.txlisthd = '[\\\\t ]*[\\\\#\\\\*]*(\\\\*|\\\\#(?:_|\\\\d+)?)' + txattr + '(?: \\\\S|\\\\.\\\\s*(?=\\\\S|\\\\n))';\n\n/***/ },\n/* 13 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/* textile list parser */\n\tvar ribbon = __webpack_require__(5);\n\tvar re = __webpack_require__(4);\n\tvar merge = __webpack_require__(1);\n\t\n\tvar _require = __webpack_require__(10);\n\t\n\tvar parseAttr = _require.parseAttr;\n\t\n\tvar _require2 = __webpack_require__(9);\n\t\n\tvar parsePhrase = _require2.parsePhrase;\n\t\n\tvar _require3 = __webpack_require__(12);\n\t\n\tvar txlisthd = _require3.txlisthd;\n\t\n\tre.pattern.txlisthd = txlisthd;\n\tvar reList = re.compile(/^((?:[:txlisthd:][^\\0]*?(?:\\r?\\n|$))+)(\\s*\\n|$)/, 's');\n\tvar reItem = re.compile(/^([#\\*]+)([^\\0]+?)(\\n(?=[:txlisthd:])|$)/, 's');\n\t\n\tfunction listPad(n) {\n\t var s = '\\n';\n\t while (n--) {\n\t s += '\\t';\n\t }\n\t return s;\n\t}\n\t\n\tfunction testList(src) {\n\t return reList.exec(src);\n\t}\n\t\n\tfunction parseList(src, options) {\n\t src = ribbon(src.replace(/(^|\\r?\\n)[\\t ]+/, '$1'));\n\t\n\t var stack = [];\n\t var currIndex = {};\n\t var lastIndex = options._lst || {};\n\t var itemIndex = 0;\n\t var listAttr = void 0;\n\t var m = void 0;\n\t var n = void 0;\n\t var s = void 0;\n\t\n\t while (m = reItem.exec(src)) {\n\t var item = ['li'];\n\t var destLevel = m[1].length;\n\t var type = m[1].substr(-1) === '#' ? 'ol' : 'ul';\n\t var newLi = null;\n\t var lst = void 0;\n\t var par = void 0;\n\t var pba = void 0;\n\t var r = void 0;\n\t\n\t // list starts and continuations\n\t if (n = /^(_|\\d+)/.exec(m[2])) {\n\t itemIndex = isFinite(n[1]) ? parseInt(n[1], 10) : lastIndex[destLevel] || currIndex[destLevel] || 1;\n\t m[2] = m[2].slice(n[1].length);\n\t }\n\t\n\t if (pba = parseAttr(m[2], 'li')) {\n\t m[2] = m[2].slice(pba[0]);\n\t pba = pba[1];\n\t }\n\t\n\t // list control\n\t if (/^\\.\\s*$/.test(m[2])) {\n\t listAttr = pba || {};\n\t src.advance(m[0]);\n\t continue;\n\t }\n\t\n\t // create nesting until we have correct level\n\t while (stack.length < destLevel) {\n\t // list always has an attribute object, this simplifies first-pba resolution\n\t lst = [type, {}, listPad(stack.length + 1), newLi = ['li']];\n\t par = stack[stack.length - 1];\n\t if (par) {\n\t par.li.push(listPad(stack.length));\n\t par.li.push(lst);\n\t }\n\t stack.push({\n\t ul: lst,\n\t li: newLi,\n\t // count attributes's found per list\n\t att: 0\n\t });\n\t currIndex[stack.length] = 1;\n\t }\n\t\n\t // remove nesting until we have correct level\n\t while (stack.length > destLevel) {\n\t r = stack.pop();\n\t r.ul.push(listPad(stack.length));\n\t // lists have a predictable structure - move pba from listitem to list\n\t if (r.att === 1 && !r.ul[3][1].substr) {\n\t merge(r.ul[1], r.ul[3].splice(1, 1)[0]);\n\t }\n\t }\n\t\n\t // parent list\n\t par = stack[stack.length - 1];\n\t\n\t if (itemIndex) {\n\t par.ul[1].start = itemIndex;\n\t currIndex[destLevel] = itemIndex;\n\t // falsy prevents this from fireing until it is set again\n\t itemIndex = 0;\n\t }\n\t if (listAttr) {\n\t // \"more than 1\" prevent attribute transfers on list close\n\t par.att = 9;\n\t merge(par.ul[1], listAttr);\n\t listAttr = null;\n\t }\n\t\n\t if (!newLi) {\n\t par.ul.push(listPad(stack.length), item);\n\t par.li = item;\n\t }\n\t if (pba) {\n\t par.li.push(pba);\n\t par.att++;\n\t }\n\t Array.prototype.push.apply(par.li, parsePhrase(m[2].trim(), options));\n\t\n\t src.advance(m[0]);\n\t currIndex[destLevel] = (currIndex[destLevel] || 0) + 1;\n\t }\n\t\n\t // remember indexes for continuations next time\n\t options._lst = currIndex;\n\t\n\t while (stack.length) {\n\t s = stack.pop();\n\t s.ul.push(listPad(stack.length));\n\t // lists have a predictable structure - move pba from listitem to list\n\t if (s.att === 1 && !s.ul[3][1].substr) {\n\t merge(s.ul[1], s.ul[3].splice(1, 1)[0]);\n\t }\n\t }\n\t\n\t return s.ul;\n\t}\n\t\n\tmodule.exports = {\n\t testList: testList,\n\t parseList: parseList\n\t};\n\n/***/ },\n/* 14 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/* definitions list parser */\n\t\n\tvar ribbon = __webpack_require__(5);\n\t\n\tvar reDeflist = /^((?:- (?:[^\\n]\\n?)+?)+:=(?: *\\n[^\\0]+?=:(?:\\n|$)|(?:[^\\0]+?(?:$|\\n(?=\\n|- )))))+/;\n\tvar reItem = /^((?:- (?:[^\\n]\\n?)+?)+):=( *\\n[^\\0]+?=:\\s*(?:\\n|$)|(?:[^\\0]+?(?:$|\\n(?=\\n|- ))))/;\n\t\n\tfunction testDefList(src) {\n\t return reDeflist.exec(src);\n\t}\n\t\n\tfunction parseDefList(src, options) {\n\t src = ribbon(src.trim());\n\t\n\t // late loading to get around the lack of non-circular-dependency support in RequireJS\n\t var parsePhrase = __webpack_require__(9).parsePhrase;\n\t var parseFlow = __webpack_require__(6).parseFlow;\n\t\n\t var deflist = ['dl', '\\n'];\n\t var terms = void 0;\n\t var def = void 0;\n\t var m = void 0;\n\t\n\t while (m = reItem.exec(src)) {\n\t // add terms\n\t terms = m[1].split(/(?:^|\\n)\\- /).slice(1);\n\t while (terms.length) {\n\t deflist.push('\\t', ['dt'].concat(parsePhrase(terms.shift().trim(), options)), '\\n');\n\t }\n\t // add definitions\n\t def = m[2].trim();\n\t deflist.push('\\t', ['dd'].concat(/=:$/.test(def) ? parseFlow(def.slice(0, -2).trim(), options) : parsePhrase(def, options)), '\\n');\n\t src.advance(m[0]);\n\t }\n\t return deflist;\n\t}\n\t\n\texports.testDefList = testDefList;\n\texports.parseDefList = parseDefList;\n\n/***/ },\n/* 15 */\n/***/ function(module, exports, __webpack_require__) {\n\n\t'use strict';\n\t\n\t/* textile table parser */\n\t\n\tvar re = __webpack_require__(4);\n\tvar merge = __webpack_require__(1);\n\tvar ribbon = __webpack_require__(5);\n\t\n\tvar _require = __webpack_require__(10);\n\t\n\tvar parseAttr = _require.parseAttr;\n\t\n\tvar _require2 = __webpack_require__(9);\n\t\n\tvar parsePhrase = _require2.parsePhrase;\n\t\n\tvar _require3 = __webpack_require__(2);\n\t\n\tvar reIndent = _require3.reIndent;\n\t\n\tvar _require4 = __webpack_require__(12);\n\t\n\tvar txattr = _require4.txattr;\n\t\n\tre.pattern.txattr = txattr;\n\t\n\tvar reTable = re.compile(/^((?:table[:txattr:]\\.(?:\\s(.+?))\\s*\\n)?(?:(?:[:txattr:]\\.[^\\n\\S]*)?\\|.*?\\|[^\\n\\S]*(?:\\n|$))+)([^\\n\\S]*\\n)?/, 's');\n\tvar reHead = /^table(_?)([^\\n]*?)\\.(?:[ \\t](.+?))?\\s*\\n/;\n\tvar reRow = re.compile(/^(?:\\|([~\\^\\-][:txattr:])\\.\\s*\\n)?([:txattr:]\\.[^\\n\\S]*)?\\|(.*?)\\|[^\\n\\S]*(\\n|$)/, 's');\n\tvar reCaption = /^\\|=([^\\n+]*)\\n/;\n\tvar reColgroup = /^\\|:([^\\n+]*)\\|[\\r\\t ]*\\n/;\n\tvar reRowgroup = /^\\|([\\^\\-~])([^\\n+]*)\\.[ \\t\\r]*\\n/;\n\t\n\tvar charToTag = {\n\t '^': 'thead',\n\t '~': 'tfoot',\n\t '-': 'tbody'\n\t};\n\t\n\tfunction parseColgroup(src) {\n\t var colgroup = ['colgroup', {}];\n\t src.split('|').forEach(function (s, isCol) {\n\t var col = isCol ? {} : colgroup[1];\n\t var d = s.trim();\n\t var m = void 0;\n\t if (d) {\n\t if (m = /^\\\\(\\d+)/.exec(d)) {\n\t col.span = +m[1];\n\t d = d.slice(m[0].length);\n\t }\n\t if (m = parseAttr(d, 'col')) {\n\t merge(col, m[1]);\n\t d = d.slice(m[0]);\n\t }\n\t if (m = /\\b\\d+\\b/.exec(d)) {\n\t col.width = +m[0];\n\t }\n\t }\n\t if (isCol) {\n\t colgroup.push('\\n\\t\\t', ['col', col]);\n\t }\n\t });\n\t return colgroup.concat(['\\n\\t']);\n\t}\n\t\n\tfunction testTable(src) {\n\t return reTable.exec(src);\n\t}\n\t\n\tfunction parseTable(src, options) {\n\t src = ribbon(src.trim());\n\t\n\t var rowgroups = [];\n\t var colgroup = void 0;\n\t var caption = void 0;\n\t var tAttr = {};\n\t var tCurr = void 0;\n\t var row = void 0;\n\t var inner = void 0;\n\t var pba = void 0;\n\t var more = void 0;\n\t var m = void 0;\n\t var extended = 0;\n\t\n\t var setRowGroup = function setRowGroup(type, pba) {\n\t tCurr = [type, pba || {}];\n\t rowgroups.push(tCurr);\n\t };\n\t\n\t if (m = reHead.exec(src)) {\n\t // parse and apply table attr\n\t src.advance(m[0]);\n\t pba = parseAttr(m[2], 'table');\n\t if (pba) {\n\t merge(tAttr, pba[1]);\n\t }\n\t if (m[3]) {\n\t tAttr.summary = m[3];\n\t }\n\t }\n\t\n\t // caption\n\t if (m = reCaption.exec(src)) {\n\t caption = ['caption'];\n\t if (pba = parseAttr(m[1], 'caption')) {\n\t caption.push(pba[1]);\n\t m[1] = m[1].slice(pba[0]);\n\t }\n\t if (/\\./.test(m[1])) {\n\t // mandatory \".\"\n\t caption.push(m[1].slice(1).replace(/\\|\\s*$/, '').trim());\n\t extended++;\n\t src.advance(m[0]);\n\t } else {\n\t caption = null;\n\t }\n\t }\n\t\n\t do {\n\t // colgroup\n\t if (m = reColgroup.exec(src)) {\n\t colgroup = parseColgroup(m[1]);\n\t extended++;\n\t }\n\t // \"rowgroup\" (tbody, thead, tfoot)\n\t else if (m = reRowgroup.exec(src)) {\n\t // PHP allows any amount of these in any order\n\t // and simply translates them straight through\n\t // the same is done here.\n\t var tag = charToTag[m[1]] || 'tbody';\n\t pba = parseAttr(m[2] + ' ', tag);\n\t setRowGroup(tag, pba && pba[1]);\n\t extended++;\n\t }\n\t // row\n\t else if (m = reRow.exec(src)) {\n\t if (!tCurr) {\n\t setRowGroup('tbody');\n\t }\n\t\n\t row = ['tr'];\n\t\n\t if (m[2] && (pba = parseAttr(m[2], 'tr'))) {\n\t // FIXME: requires \"\\.\\s?\" -- else what ?\n\t row.push(pba[1]);\n\t }\n\t\n\t tCurr.push('\\n\\t\\t', row);\n\t inner = ribbon(m[3]);\n\t\n\t do {\n\t inner.save();\n\t\n\t // cell loop\n\t var th = inner.startsWith('_');\n\t var cell = [th ? 'th' : 'td'];\n\t if (th) {\n\t inner.advance(1);\n\t }\n\t\n\t pba = parseAttr(inner, 'td');\n\t if (pba) {\n\t inner.advance(pba[0]);\n\t cell.push(pba[1]); // FIXME: don't do this if next text fails\n\t }\n\t\n\t if (pba || th) {\n\t var p = /^\\.\\s*/.exec(inner);\n\t if (p) {\n\t inner.advance(p[0]);\n\t } else {\n\t cell = ['td'];\n\t inner.load();\n\t }\n\t }\n\t\n\t var mx = /^(==.*?==|[^\\|])*/.exec(inner);\n\t cell = cell.concat(parsePhrase(mx[0], options));\n\t row.push('\\n\\t\\t\\t', cell);\n\t more = inner.valueOf().charAt(mx[0].length) === '|';\n\t inner.advance(mx[0].length + 1);\n\t } while (more);\n\t\n\t row.push('\\n\\t\\t');\n\t }\n\t //\n\t if (m) {\n\t src.advance(m[0]);\n\t }\n\t } while (m);\n\t\n\t // assemble table\n\t var table = ['table', tAttr];\n\t if (extended) {\n\t if (caption) {\n\t table.push('\\n\\t', caption);\n\t }\n\t if (colgroup) {\n\t table.push('\\n\\t', colgroup);\n\t }\n\t rowgroups.forEach(function (tbody) {\n\t table.push('\\n\\t', tbody.concat(['\\n\\t']));\n\t });\n\t } else {\n\t table = table.concat(reIndent(rowgroups[0].slice(2), -1));\n\t }\n\t\n\t table.push('\\n');\n\t return table;\n\t}\n\t\n\tmodule.exports = {\n\t parseColgroup: parseColgroup,\n\t parseTable: parseTable,\n\t testTable: testTable\n\t};\n\n/***/ }\n/******/ ])\n});\n;\n\n\n/** WEBPACK FOOTER **\n ** textile.min.js\n **/"," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId])\n \t\t\treturn installedModules[moduleId].exports;\n\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\texports: {},\n \t\t\tid: moduleId,\n \t\t\tloaded: false\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.loaded = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(0);\n\n\n\n/** WEBPACK FOOTER **\n ** webpack/bootstrap 993a960178192ed49935\n **/","/*\n** Textile parser for JavaScript\n**\n** Copyright (c) 2012 Borgar Þorsteinsson (MIT License).\n**\n*/\n\nconst merge = require( './merge' );\nconst { toHTML } = require( './jsonml' );\nconst { parseFlow } = require( './textile/flow' );\nconst { parseHtml } = require( './html' );\n\nfunction textile ( txt, opt ) {\n // get a throw-away copy of options\n opt = merge( merge({}, textile.defaults ), opt || {});\n // run the converter\n return parseFlow( txt, opt ).map( toHTML ).join( '' );\n};\nmodule.exports = textile;\n\n// options\ntextile.defaults = {\n // single-line linebreaks are converted to
    by default\n 'breaks': true\n};\ntextile.setOptions = textile.setoptions = function ( opt ) {\n merge( textile.defaults, opt );\n return this;\n};\n\ntextile.parse = textile.convert = textile;\ntextile.html_parser = parseHtml;\n\ntextile.jsonml = function ( txt, opt ) {\n // get a throw-away copy of options\n opt = merge( merge({}, textile.defaults ), opt || {});\n // parse and return tree\n return [ 'html' ].concat( parseFlow( txt, opt ) );\n};\ntextile.serialize = toHTML;\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/index.js\n **/","// merge object b properties into object a\nmodule.exports = function merge ( a, b ) {\n if ( b ) {\n for ( const k in b ) {\n a[ k ] = b[ k ];\n }\n }\n return a;\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/merge.js\n **/","/*\n** JSONML helper methods - http://www.jsonml.org/\n**\n** This provides the `JSONML` object, which contains helper\n** methods for rendering JSONML to HTML.\n**\n** Note that the tag ! is taken to mean comment, this is however\n** not specified in the JSONML spec.\n*/\n\nconst singletons = require( './html' ).singletons;\n\n// drop or add tab levels to JsonML tree\nfunction reIndent ( ml, shiftBy ) {\n // a bit obsessive, but there we are...\n if ( !shiftBy ) {\n return ml;\n }\n return ml.map( function ( s ) {\n if ( /^\\n\\t+/.test( s ) ) {\n if ( shiftBy < 0 ) {\n s = s.slice( 0, shiftBy );\n }\n else {\n for ( let i = 0; i < shiftBy; i++ ) {\n s += '\\t';\n }\n }\n }\n else if ( Array.isArray( s ) ) {\n return reIndent( s, shiftBy );\n }\n return s;\n });\n}\n\nfunction escape ( text, escapeQuotes ) {\n return text.replace( /&(?!(#\\d{2,}|#x[\\da-fA-F]{2,}|[a-zA-Z][a-zA-Z1-4]{1,6});)/g, '&' )\n .replace( //g, '>' )\n .replace( /\"/g, escapeQuotes ? '"' : '\"' )\n .replace( /'/g, escapeQuotes ? ''' : \"'\" );\n}\n\nfunction toHTML ( jsonml ) {\n jsonml = jsonml.concat();\n\n // basic case\n if ( typeof jsonml === 'string' ) {\n return escape( jsonml );\n }\n\n const tag = jsonml.shift();\n let attributes = {};\n let tagAttrs = '';\n const content = [];\n\n if ( jsonml.length && typeof jsonml[0] === 'object' && !Array.isArray( jsonml[0] ) ) {\n attributes = jsonml.shift();\n }\n\n while ( jsonml.length ) {\n content.push( toHTML( jsonml.shift() ) );\n }\n\n for ( const a in attributes ) {\n tagAttrs += ( attributes[a] == null )\n ? ` ${ a }`\n : ` ${ a }=\"${ escape( String( attributes[a] ), true ) }\"`;\n }\n\n // be careful about adding whitespace here for inline elements\n if ( tag === '!' ) {\n return ``;\n }\n else if ( tag in singletons ) {\n return `<${ tag }${ tagAttrs } />`;\n }\n else {\n return `<${ tag }${ tagAttrs }>${ content.join( '' ) }`;\n }\n}\n\nmodule.exports = {\n reIndent: reIndent,\n toHTML: toHTML,\n escape: escape\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/jsonml.js\n **/","const re = require( './re' );\nconst ribbon = require( './ribbon' );\n\nre.pattern.html_id = '[a-zA-Z][a-zA-Z\\\\d:]*';\nre.pattern.html_attr = '(?:\"[^\"]+\"|\\'[^\\']+\\'|[^>\\\\s]+)';\n\nconst reAttr = re.compile( /^\\s*([^=\\s]+)(?:\\s*=\\s*(\"[^\"]+\"|'[^']+'|[^>\\s]+))?/ );\nconst reComment = re.compile( /^/, 's' );\nconst reEndTag = re.compile( /^<\\/([:html_id:])([^>]*)>/ );\nconst reTag = re.compile( /^<([:html_id:])((?:\\s[^=\\s\\/]+(?:\\s*=\\s*[:html_attr:])?)+)?\\s*(\\/?)>(\\n*)/ );\nconst reHtmlTagBlock = re.compile( /^\\s*<([:html_id:](?::[a-zA-Z\\d]+)*)((?:\\s[^=\\s\\/]+(?:\\s*=\\s*[:html_attr:])?)+)?\\s*(\\/?)>(\\n*)/ );\n\n// area, base, basefont, bgsound, br, col, command, embed, frame, hr,\n// img, input, keygen, link, meta, param, source, track or wbr\nconst singletons = {\n br: 1,\n hr: 1,\n img: 1,\n link: 1,\n meta: 1,\n wbr: 1,\n area: 1,\n param: 1,\n input: 1,\n option: 1,\n base: 1,\n col: 1\n};\n\nfunction allowAll () {\n return true;\n}\n\nfunction testComment ( src ) {\n return reComment.exec( src );\n}\n\nfunction testOpenTagBlock ( src ) {\n return reHtmlTagBlock.exec( src );\n}\n\nfunction testOpenTag ( src ) {\n return reTag.exec( src );\n}\n\nfunction testCloseTag ( src ) {\n return reEndTag.exec( src );\n}\n\nfunction parseHtmlAttr ( attrSrc ) {\n // parse ATTR and add to element\n const attr = {};\n let m;\n while ( ( m = reAttr.exec( attrSrc ) ) ) {\n attr[ m[1] ] = ( typeof m[2] === 'string' ) ? m[2].replace( /^([\"'])(.*)\\1$/, '$2' ) : null;\n attrSrc = attrSrc.slice( m[0].length );\n }\n return attr;\n}\n\n// This \"indesciminately\" parses HTML text into a list of JSON-ML element\n// No steps are taken however to prevent things like

    - user can still create nonsensical but \"well-formed\" markup\nfunction parseHtml ( src, whitelistTags ) {\n const root = [];\n let list = root;\n const _stack = [];\n const oktag = whitelistTags ? function ( tag ) { return tag in whitelistTags; } : allowAll;\n let m;\n let tag;\n\n src = ( typeof src === 'string' ) ? ribbon( src ) : src;\n // loop\n do {\n // comment\n if ( ( m = testComment( src ) ) && oktag( '!' ) ) {\n src.advance( m[0] );\n list.push( [ '!', m[1] ] );\n }\n\n // end tag\n else if ( ( m = testCloseTag( src ) ) && oktag( m[1] ) ) {\n tag = m[1];\n if ( _stack.length ) {\n for ( let i = _stack.length - 1; i >= 0; i-- ) {\n const head = _stack[i];\n if ( head[0] === tag ) {\n _stack.splice( i );\n list = _stack[_stack.length - 1] || root;\n break;\n }\n }\n }\n src.advance( m[0] );\n }\n\n // open/void tag\n else if ( ( m = testOpenTag( src ) ) && oktag( m[1] ) ) {\n src.advance( m[0] );\n tag = m[1];\n const single = m[3] || m[1] in singletons;\n const tail = m[4];\n const element = [ tag ];\n\n // attributes\n if ( m[2] ) {\n element.push( parseHtmlAttr( m[2] ) );\n }\n\n // single tag\n if ( single ) {\n // let us add the element and continue our quest...\n list.push( element );\n if ( tail ) {\n list.push( tail );\n }\n }\n // open tag\n else {\n if ( tail ) {\n element.push( tail );\n }\n\n // TODO: some things auto close other things: ,
  • ,

    , \n // if ( tag === 'p' && _stack.length ) {\n // var seek = /^(p)$/;\n // for (var i=_stack.length-1; i>=0; i--) {\n // var head = _stack[i];\n // if ( seek.test( head[0] ) /* === tag */ ) {\n // //src.advance( m[0] );\n // _stack.splice( i );\n // list = _stack[i] || root;\n // }\n // }\n // }\n\n // TODO: some elements can move parser into \"text\" mode\n // style, xmp, iframe, noembed, noframe, textarea, title, script, noscript, plaintext\n // if ( /^(script)$/.test( tag ) ) { }\n\n _stack.push( element );\n list.push( element );\n list = element;\n }\n }\n // text content\n else {\n // no match, move by all \"uninteresting\" chars\n m = /([^<]+|[^\\0])/.exec( src );\n if ( m ) {\n list.push( m[0] );\n }\n src.advance( m ? m[0].length || 1 : 1 );\n }\n }\n while ( src.valueOf() );\n\n return root;\n}\n\nmodule.exports = {\n singletons: singletons,\n parseHtml: parseHtml,\n parseHtmlAttr: parseHtmlAttr,\n testCloseTag: testCloseTag,\n testOpenTagBlock: testOpenTagBlock,\n testOpenTag: testOpenTag,\n testComment: testComment\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/html.js\n **/","/*\n** Regular Expression helper methods\n**\n** This provides the `re` object, which contains several helper\n** methods for working with big regular expressions (soup).\n**\n*/\n\nconst _cache = {};\n\nconst re = module.exports = {\n\n pattern: {\n 'punct': '[!-/:-@\\\\[\\\\\\\\\\\\]-`{-~]',\n 'space': '\\\\s'\n },\n\n escape: function ( src ) {\n return src.replace( /[\\-\\[\\]\\{\\}\\(\\)\\*\\+\\?\\.,\\\\\\^\\$\\|#\\s]/g, '\\\\$&' );\n },\n\n collapse: function ( src ) {\n return src.replace( /(?:#.*?(?:\\n|$))/g, '' )\n .replace( /\\s+/g, '' );\n },\n\n expandPatterns: function ( src ) {\n // TODO: provide escape for patterns: \\[:pattern:] ?\n return src.replace( /\\[:\\s*(\\w+)\\s*:\\]/g, function ( m, k ) {\n const ex = re.pattern[k];\n if ( ex ) {\n return re.expandPatterns( ex );\n }\n else {\n throw new Error( 'Pattern ' + m + ' not found in ' + src );\n }\n });\n },\n\n isRegExp: function ( r ) {\n return Object.prototype.toString.call( r ) === '[object RegExp]';\n },\n\n compile: function ( src, flags ) {\n if ( re.isRegExp( src ) ) {\n if ( arguments.length === 1 ) { // no flags arg provided, use the RegExp one\n flags = ( src.global ? 'g' : '' ) +\n ( src.ignoreCase ? 'i' : '' ) +\n ( src.multiline ? 'm' : '' );\n }\n src = src.source;\n }\n // don't do the same thing twice\n const ckey = src + ( flags || '' );\n if ( ckey in _cache ) {\n return _cache[ ckey ];\n }\n // allow classes\n let rx = re.expandPatterns( src );\n // allow verbose expressions\n if ( flags && /x/.test( flags ) ) {\n rx = re.collapse( rx );\n }\n // allow dotall expressions\n if ( flags && /s/.test( flags ) ) {\n rx = rx.replace( /([^\\\\])\\./g, '$1[^\\\\0]' );\n }\n // TODO: test if MSIE and add replace \\s with [\\s\\u00a0] if it is?\n // clean flags and output new regexp\n flags = ( flags || '' ).replace( /[^gim]/g, '' );\n return ( _cache[ ckey ] = new RegExp( rx, flags ) );\n }\n\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/re.js\n **/","module.exports = function ribbon ( feed ) {\n const org = String( feed );\n let slot = null;\n let pos = 0;\n\n return {\n\n save: function () {\n slot = pos;\n },\n\n load: function () {\n pos = slot;\n feed = org.slice( pos );\n this.$ = feed;\n },\n\n advance: function ( n ) {\n pos += ( typeof n === 'string' ) ? n.length : n;\n feed = org.slice( pos );\n this.$ = feed;\n return feed;\n },\n\n lookbehind: function ( nchars ) {\n nchars = nchars == null ? 1 : nchars;\n return org.slice( pos - nchars, pos );\n },\n\n startsWith: function ( s ) {\n return feed.substring( 0, s.length ) === s;\n },\n\n valueOf: function () {\n this.$ = feed;\n return feed;\n },\n\n toString: function () {\n this.$ = feed;\n return feed;\n }\n\n };\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/ribbon.js\n **/","/*\n** textile flow content parser\n*/\nconst builder = require( '../builder' );\nconst ribbon = require( '../ribbon' );\nconst re = require( '../re' );\nconst fixLinks = require( '../fixlinks' );\n\nconst { parseHtml, parseHtmlAttr, singletons, testComment, testOpenTagBlock } = require( '../html' );\n\nconst { parsePhrase } = require( './phrase' );\nconst { copyAttr, parseAttr } = require( './attr' );\nconst { testList, parseList } = require( './list' );\nconst { testDefList, parseDefList } = require( './deflist' );\nconst { testTable, parseTable } = require( './table' );\n\nconst { txblocks, txlisthd, txattr } = require( './re_ext' );\nre.pattern.txblocks = txblocks;\nre.pattern.txlisthd = txlisthd;\nre.pattern.txattr = txattr;\n\n// HTML tags allowed in the document (root) level that trigger HTML parsing\nconst allowedBlocktags = {\n 'p': 0,\n 'hr': 0,\n 'ul': 1,\n 'ol': 0,\n 'li': 0,\n 'div': 1,\n 'pre': 0,\n 'object': 1,\n 'script': 0,\n 'noscript': 0,\n 'blockquote': 1,\n 'notextile': 1\n};\n\nconst reBlock = re.compile( /^([:txblocks:])/ );\n// const reBlockSE = re.compile( /^[:txblocks:]$/ );\nconst reBlockNormal = re.compile( /^(.*?)($|\\r?\\n(?=[:txlisthd:])|\\r?\\n(?:\\s*\\n|$)+)/, 's' );\nconst reBlockExtended = re.compile( /^(.*?)($|\\r?\\n(?=[:txlisthd:])|\\r?\\n+(?=[:txblocks:][:txattr:]\\.))/, 's' );\nconst reRuler = /^(\\-\\-\\-+|\\*\\*\\*+|___+)(\\r?\\n\\s+|$)/;\nconst reLinkRef = re.compile( /^\\[([^\\]]+)\\]((?:https?:\\/\\/|\\/)\\S+)(?:\\s*\\n|$)/ );\nconst reFootnoteDef = /^fn\\d+$/;\n\nfunction paragraph ( s, tag, pba, linebreak, options ) {\n tag = tag || 'p';\n let out = [];\n s.split( /(?:\\r?\\n){2,}/ ).forEach( function ( bit, i ) {\n if ( tag === 'p' && /^\\s/.test( bit ) ) {\n // no-paragraphs\n // WTF?: Why does Textile not allow linebreaks in spaced lines\n bit = bit.replace( /\\r?\\n[\\t ]/g, ' ' ).trim();\n out = out.concat( parsePhrase( bit, options ) );\n }\n else {\n if ( linebreak && i ) { out.push( linebreak ); }\n out.push( pba ? [ tag, pba ].concat( parsePhrase( bit, options ) )\n : [ tag ].concat( parsePhrase( bit, options ) ) );\n }\n });\n return out;\n};\n\nfunction parseFlow ( src, options ) {\n const list = builder();\n\n let linkRefs;\n let m;\n\n src = ribbon( src.replace( /^( *\\r?\\n)+/, '' ) );\n\n // loop\n while ( src.valueOf() ) {\n src.save();\n\n // link_ref -- this goes first because it shouldn't trigger a linebreak\n if ( ( m = reLinkRef.exec( src ) ) ) {\n if ( !linkRefs ) { linkRefs = {}; }\n src.advance( m[0] );\n linkRefs[m[1]] = m[2];\n continue;\n }\n\n // add linebreak\n list.linebreak();\n\n // named block\n if ( ( m = reBlock.exec( src ) ) ) {\n src.advance( m[0] );\n const blockType = m[0];\n let pba = parseAttr( src, blockType );\n\n if ( pba ) {\n src.advance( pba[0] );\n pba = pba[1];\n }\n if ( ( m = /^\\.(\\.?)(?:\\s|(?=:))/.exec( src ) ) ) {\n // FIXME: this whole copyAttr seems rather strange?\n // slurp rest of block\n const extended = !!m[1];\n const reBlockGlob = ( extended ? reBlockExtended : reBlockNormal );\n m = reBlockGlob.exec( src.advance( m[0] ) );\n src.advance( m[0] );\n // bq | bc | notextile | pre | h# | fn# | p | ###\n if ( blockType === 'bq' ) {\n let inner = m[1];\n if ( ( m = /^:(\\S+)\\s+/.exec( inner ) ) ) {\n if ( !pba ) { pba = {}; }\n pba.cite = m[1];\n inner = inner.slice( m[0].length );\n }\n // RedCloth adds all attr to both: this is bad because it produces duplicate IDs\n const par = paragraph( inner, 'p', copyAttr( pba, { 'cite': 1, 'id': 1 }), '\\n', options );\n list.add( [ 'blockquote', pba, '\\n' ].concat( par ).concat( [ '\\n' ] ) );\n // FIXME: looks like .linebreak can work here\n }\n else if ( blockType === 'bc' ) {\n const subPba = ( pba ) ? copyAttr( pba, { 'id': 1 }) : null;\n list.add( [ 'pre', pba, ( subPba ? [ 'code', subPba, m[1] ] : [ 'code', m[1] ] ) ] );\n }\n else if ( blockType === 'notextile' ) {\n list.merge( parseHtml( m[1] ) );\n }\n else if ( blockType === '###' ) {\n // ignore the insides\n }\n else if ( blockType === 'pre' ) {\n // I disagree with RedCloth, but agree with PHP here:\n // \"pre(foo#bar).. line1\\n\\nline2\" prevents multiline preformat blocks\n // ...which seems like the whole point of having an extended pre block?\n list.add( [ 'pre', pba, m[1] ] );\n }\n else if ( reFootnoteDef.test( blockType ) ) { // footnote\n // Need to be careful: RedCloth fails \"fn1(foo#m). footnote\" -- it confuses the ID\n const fnid = blockType.replace( /\\D+/g, '' );\n if ( !pba ) { pba = {}; }\n pba.class = ( pba['class'] ? pba['class'] + ' ' : '' ) + 'footnote';\n pba.id = 'fn' + fnid;\n list.add( [ 'p', pba, [ 'a', { 'href': '#fnr' + fnid }, [ 'sup', fnid ] ], ' ' ]\n .concat( parsePhrase( m[1], options ) ) );\n }\n else { // heading | paragraph\n list.merge( paragraph( m[1], blockType, pba, '\\n', options ) );\n }\n continue;\n }\n else {\n src.load();\n }\n }\n\n // HTML comment\n if ( ( m = testComment( src ) ) ) {\n src.advance( m[0] + ( /(?:\\s*\\n+)+/.exec( src ) || [] )[0] );\n list.add( [ '!', m[1] ] );\n continue;\n }\n\n // block HTML\n if ( ( m = testOpenTagBlock( src ) ) ) {\n const tag = m[1];\n const single = m[3] || tag in singletons;\n const tail = m[4];\n\n // Unsurprisingly, all Textile implementations I have tested have trouble parsing simple HTML:\n //\n // \"
    a\\n
    b\\n
    c\\n
    d\"\n //\n // I simply match them here as there is no way anyone is using nested HTML today, or if they\n // are, then this will at least output less broken HTML as redundant tags will get quoted.\n\n // Is block tag? ...\n if ( tag in allowedBlocktags ) {\n src.advance( m[0] );\n\n let element = [ tag ];\n\n if ( m[2] ) {\n element.push( parseHtmlAttr( m[2] ) );\n }\n\n // single tag\n if ( single ) {\n // let us add the element and continue our quest...\n list.add( element );\n continue;\n }\n // block\n else {\n // gulp up the rest of this block...\n const reEndTag = re.compile( `^(.*?)(\\\\s*)()(\\\\s*)`, 's' );\n if ( ( m = reEndTag.exec( src ) ) ) {\n src.advance( m[0] );\n if ( tag === 'pre' ) {\n element.push( tail );\n element = element.concat( parseHtml( m[1].replace( /(\\r?\\n)+$/, '' ), { 'code': 1 }) );\n if ( m[2] ) { element.push( m[2] ); }\n list.add( element );\n }\n else if ( tag === 'notextile' ) {\n element = parseHtml( m[1].trim() );\n list.merge( element );\n }\n else if ( tag === 'script' || tag === 'noscript' ) {\n element.push( tail + m[1] );\n list.add( element );\n }\n else {\n // These strange (and unnecessary) linebreak tests are here to get the\n // tests working perfectly. In reality, this doesn't matter one bit.\n if ( /\\n/.test( tail ) ) { element.push( '\\n' ); }\n if ( /\\n/.test( m[1] ) ) {\n element = element.concat( parseFlow( m[1], options ) );\n }\n else {\n element = element.concat( parsePhrase( m[1].replace( /^ +/, '' ), options ) );\n }\n if ( /\\n/.test( m[2] ) ) { element.push( '\\n' ); }\n\n list.add( element );\n }\n continue;\n }\n }\n }\n src.load();\n }\n\n // ruler\n if ( ( m = reRuler.exec( src ) ) ) {\n src.advance( m[0] );\n list.add( [ 'hr' ] );\n continue;\n }\n\n // list\n if ( ( m = testList( src ) ) ) {\n src.advance( m[0] );\n list.add( parseList( m[0], options ) );\n continue;\n }\n\n // definition list\n if ( ( m = testDefList( src ) ) ) {\n src.advance( m[0] );\n list.add( parseDefList( m[0], options ) );\n continue;\n }\n\n // table\n if ( ( m = testTable( src ) ) ) {\n src.advance( m[0] );\n list.add( parseTable( m[1], options ) );\n continue;\n }\n\n // paragraph\n m = reBlockNormal.exec( src );\n list.merge( paragraph( m[1], 'p', undefined, '\\n', options ) );\n src.advance( m[0] );\n }\n\n return linkRefs ? fixLinks( list.get(), linkRefs ) : list.get();\n}\n\nexports.parseFlow = parseFlow;\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/flow.js\n **/","module.exports = function builder ( initArr ) {\n const arr = Array.isArray( initArr ) ? initArr : [];\n\n return {\n add: function ( node ) {\n if ( typeof node === 'string' &&\n typeof arr[ arr.length - 1 ] === 'string' ) {\n // join if possible\n arr[ arr.length - 1 ] += node;\n }\n else if ( Array.isArray( node ) ) {\n arr.push( node.filter( s => s !== undefined ) );\n }\n else if ( node ) {\n arr.push( node );\n }\n return this;\n },\n\n merge: function ( arr ) {\n for ( let i = 0, l = arr.length; i < l; i++ ) {\n this.add( arr[i] );\n }\n return this;\n },\n\n linebreak: function () {\n if ( arr.length ) {\n this.add( '\\n' );\n }\n },\n\n get: function () {\n return arr;\n }\n };\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/builder.js\n **/","// recurse the tree and swap out any \"href\" attributes\n// this uses the context as the replace dictionary so it can be fed to Array#map\nmodule.exports = function fixLinks ( ml, dict ) {\n if ( Array.isArray( ml ) ) {\n if ( ml[0] === 'a' ) { // found a link\n const attr = ml[1];\n if ( typeof attr === 'object' && 'href' in attr && attr.href in dict ) {\n attr.href = dict[attr.href];\n }\n }\n for ( let i = 0, l = ml.length; i < l; i++ ) {\n if ( Array.isArray( ml[i] ) ) {\n fixLinks( ml[i], dict );\n }\n }\n }\n return ml;\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/fixlinks.js\n **/","/* textile inline parser */\n\nconst ribbon = require( '../ribbon' );\nconst builder = require( '../builder' );\nconst re = require( '../re' );\n\nconst { parseAttr } = require( './attr' );\nconst { parseGlyph } = require( './glyph' );\nconst { parseHtmlAttr, singletons, testComment, testOpenTag } = require( '../html' );\n\nconst { ucaps, txattr, txcite } = require( './re_ext' );\nre.pattern.txattr = txattr;\nre.pattern.txcite = txcite;\nre.pattern.ucaps = ucaps;\n\nconst phraseConvert = {\n '*': 'strong',\n '**': 'b',\n '??': 'cite',\n '_': 'em',\n '__': 'i',\n '-': 'del',\n '%': 'span',\n '+': 'ins',\n '~': 'sub',\n '^': 'sup',\n '@': 'code'\n};\n\nconst rePhrase = /^([\\[\\{]?)(__?|\\*\\*?|\\?\\?|[\\-\\+\\^~@%])/;\nconst reImage = re.compile( /^!(?!\\s)([:txattr:](?:\\.[^\\n\\S]|\\.(?:[^\\.\\/]))?)([^!\\s]+?) ?(?:\\(((?:[^\\(\\)]+|\\([^\\(\\)]+\\))+)\\))?!(?::([^\\s]+?(?=[!-\\.:-@\\[\\\\\\]-`{-~](?:$|\\s)|\\s|$)))?/ );\nconst reImageFenced = re.compile( /^\\[!(?!\\s)([:txattr:](?:\\.[^\\n\\S]|\\.(?:[^\\.\\/]))?)([^!\\s]+?) ?(?:\\(((?:[^\\(\\)]+|\\([^\\(\\)]+\\))+)\\))?!(?::([^\\s]+?(?=[!-\\.:-@\\[\\\\\\]-`{-~](?:$|\\s)|\\s|$)))?\\]/ );\n// NB: there is an exception in here to prevent matching \"TM)\"\nconst reCaps = re.compile( /^((?!TM\\)|tm\\))[[:ucaps:]](?:[[:ucaps:]\\d]{1,}(?=\\()|[[:ucaps:]\\d]{2,}))(?:\\((.*?)\\))?(?=\\W|$)/ );\nconst reLink = re.compile( /^\"(?!\\s)((?:[^\\n\"]|\"(?![\\s:])[^\\n\"]+\"(?!:))+)\"[:txcite:]/ );\nconst reLinkFenced = /^\\[\"([^\\n]+?)\":((?:\\[[a-z0-9]*\\]|[^\\]])+)\\]/;\nconst reLinkTitle = /\\s*\\(((?:\\([^\\(\\)]*\\)|[^\\(\\)])+)\\)$/;\nconst reFootnote = /^\\[(\\d+)(!?)\\]/;\n\nfunction parsePhrase ( src, options ) {\n src = ribbon( src );\n\n const list = builder();\n let m;\n let pba;\n\n // loop\n do {\n src.save();\n\n // linebreak -- having this first keeps it from messing to much with other phrases\n if ( src.startsWith( '\\r\\n' ) ) {\n src.advance( 1 ); // skip cartridge returns\n }\n if ( src.startsWith( '\\n' ) ) {\n src.advance( 1 );\n if ( options.breaks ) {\n list.add( [ 'br' ] );\n }\n list.add( '\\n' );\n continue;\n }\n\n // inline notextile\n if ( ( m = /^==(.*?)==/.exec( src ) ) ) {\n src.advance( m[0] );\n list.add( m[1] );\n continue;\n }\n\n // lookbehind => /([\\s>.,\"'?!;:])$/\n const behind = src.lookbehind( 1 );\n const boundary = !behind || /^[\\s>.,\"'?!;:()]$/.test( behind );\n // FIXME: need to test right boundary for phrases as well\n if ( ( m = rePhrase.exec( src ) ) && ( boundary || m[1] ) ) {\n src.advance( m[0] );\n const tok = m[2];\n const fence = m[1];\n const phraseType = phraseConvert[tok];\n const code = phraseType === 'code';\n\n if ( ( pba = !code && parseAttr( src, phraseType, tok ) ) ) {\n src.advance( pba[0] );\n pba = pba[1];\n }\n // FIXME: if we can't match the fence on the end, we should output fence-prefix as normal text\n // seek end\n let mMid;\n let mEnd;\n if ( fence === '[' ) {\n mMid = '^(.*?)';\n mEnd = '(?:])';\n }\n else if ( fence === '{' ) {\n mMid = '^(.*?)';\n mEnd = '(?:})';\n }\n else {\n const t1 = re.escape( tok.charAt( 0 ) );\n mMid = ( code ) ? '^(\\\\S+|\\\\S+.*?\\\\S)'\n : `^([^\\\\s${ t1 }]+|[^\\\\s${ t1 }].*?\\\\S(${ t1 }*))`;\n mEnd = '(?=$|[\\\\s.,\"\\'!?;:()«»„“”‚‘’])';\n }\n const rx = re.compile( `${ mMid }(${ re.escape( tok ) })${ mEnd }` );\n if ( ( m = rx.exec( src ) ) && m[1] ) {\n src.advance( m[0] );\n if ( code ) {\n list.add( [ phraseType, m[1] ] );\n }\n else {\n list.add( [ phraseType, pba ].concat( parsePhrase( m[1], options ) ) );\n }\n continue;\n }\n // else\n src.load();\n }\n\n // image\n if ( ( m = reImage.exec( src ) ) || ( m = reImageFenced.exec( src ) ) ) {\n src.advance( m[0] );\n\n pba = m[1] && parseAttr( m[1], 'img' );\n const attr = pba ? pba[1] : { 'src': '' };\n let img = [ 'img', attr ];\n attr.src = m[2];\n attr.alt = m[3] ? ( attr.title = m[3] ) : '';\n\n if ( m[4] ) { // +cite causes image to be wraped with a link (or link_ref)?\n // TODO: support link_ref for image cite\n img = [ 'a', { 'href': m[4] }, img ];\n }\n list.add( img );\n continue;\n }\n\n // html comment\n if ( ( m = testComment( src ) ) ) {\n src.advance( m[0] );\n list.add( [ '!', m[1] ] );\n continue;\n }\n // html tag\n // TODO: this seems to have a lot of overlap with block tags... DRY?\n if ( ( m = testOpenTag( src ) ) ) {\n src.advance( m[0] );\n const tag = m[1];\n const single = m[3] || m[1] in singletons;\n let element = [ tag ];\n const tail = m[4];\n if ( m[2] ) {\n element.push( parseHtmlAttr( m[2] ) );\n }\n if ( single ) { // single tag\n list.add( element ).add( tail );\n continue;\n }\n else { // need terminator\n // gulp up the rest of this block...\n const reEndTag = re.compile( `^(.*?)()`, 's' );\n if ( ( m = reEndTag.exec( src ) ) ) {\n src.advance( m[0] );\n if ( tag === 'code' ) {\n element.push( tail, m[1] );\n }\n else if ( tag === 'notextile' ) {\n list.merge( parsePhrase( m[1], options ) );\n continue;\n }\n else {\n element = element.concat( parsePhrase( m[1], options ) );\n }\n list.add( element );\n continue;\n }\n // end tag is missing, treat tag as normal text...\n }\n src.load();\n }\n\n // footnote\n if ( ( m = reFootnote.exec( src ) ) && /\\S/.test( behind ) ) {\n src.advance( m[0] );\n list.add( [ 'sup', { 'class': 'footnote', 'id': 'fnr' + m[1] },\n ( m[2] === '!' ? m[1] // \"!\" suppresses the link\n : [ 'a', { href: '#fn' + m[1] }, m[1] ] )\n ] );\n continue;\n }\n\n // caps / abbr\n if ( ( m = reCaps.exec( src ) ) ) {\n src.advance( m[0] );\n let caps = [ 'span', { 'class': 'caps' }, m[1] ];\n if ( m[2] ) {\n // FIXME: use , not acronym!\n caps = [ 'acronym', { 'title': m[2] }, caps ];\n }\n list.add( caps );\n continue;\n }\n\n // links\n if ( ( boundary && ( m = reLink.exec( src ) ) ) ||\n ( m = reLinkFenced.exec( src ) ) ) {\n src.advance( m[0] );\n let title = m[1].match( reLinkTitle );\n let inner = ( title ) ? m[1].slice( 0, m[1].length - title[0].length ) : m[1];\n if ( ( pba = parseAttr( inner, 'a' ) ) ) {\n inner = inner.slice( pba[0] );\n pba = pba[1];\n }\n else {\n pba = {};\n }\n if ( title && !inner ) {\n inner = title[0];\n title = '';\n }\n pba.href = m[2];\n if ( title ) { pba.title = title[1]; }\n list.add( [ 'a', pba ].concat( parsePhrase( inner.replace( /^(\\.?\\s*)/, '' ), options ) ) );\n continue;\n }\n\n // no match, move by all \"uninteresting\" chars\n m = /([a-zA-Z0-9,.':]+|[ \\f\\r\\t\\v\\xA0\\u2028\\u2029]+|[^\\0])/.exec( src );\n if ( m ) {\n list.add( m[0] );\n }\n src.advance( m ? m[0].length || 1 : 1 );\n }\n while ( src.valueOf() );\n\n return list.get().map( parseGlyph );\n}\n\nexports.parsePhrase = parsePhrase;\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/phrase.js\n **/","const reClassid = /^\\(([^\\(\\)\\n]+)\\)/;\nconst rePaddingL = /^(\\(+)/;\nconst rePaddingR = /^(\\)+)/;\nconst reAlignBlock = /^(<>|<|>|=)/;\nconst reAlignImg = /^(<|>|=)/;\nconst reVAlign = /^(~|\\^|\\-)/;\nconst reColSpan = /^\\\\(\\d+)/;\nconst reRowSpan = /^\\/(\\d+)/;\nconst reStyles = /^\\{([^\\}]*)\\}/;\nconst reCSS = /^\\s*([^:\\s]+)\\s*:\\s*(.+)\\s*$/;\nconst reLang = /^\\[([^\\[\\]\\n]+)\\]/;\n\nconst pbaAlignLookup = {\n '<': 'left',\n '=': 'center',\n '>': 'right',\n '<>': 'justify'\n};\n\nconst pbaVAlignLookup = {\n '~': 'bottom',\n '^': 'top',\n '-': 'middle'\n};\n\nfunction copyAttr ( s, blacklist ) {\n if ( !s ) { return undefined; }\n const d = {};\n for ( const k in s ) {\n if ( k in s && ( !blacklist || !( k in blacklist ) ) ) {\n d[ k ] = s[ k ];\n }\n }\n return d;\n}\n\nfunction testBlock ( name ) {\n // \"in\" test would be better but what about fn#.?\n return /^(?:table|t[dh]|t(?:foot|head|body)|b[qc]|div|notextile|pre|h[1-6]|fn\\\\d+|p|###)$/.test( name );\n}\n\n/*\n The attr bit causes massive problems for span elements when parentheses are used.\n Parentheses are a total mess and, unsurprisingly, cause trip-ups:\n\n RC: `_{display:block}(span) span (span)_` -> `(span) span (span)`\n PHP: `_{display:block}(span) span (span)_` -> `(span) span (span)`\n\n PHP and RC seem to mostly solve this by not parsing a final attr parens on spans if the\n following character is a non-space. I've duplicated that: Class/ID is not matched on spans\n if it is followed by `endToken` or .\n\n Lang is not matched here if it is followed by the end token. Theoretically I could limit the lang\n attribute to /^\\[[a-z]{2+}(\\-[a-zA-Z0-9]+)*\\]/ because Textile is layered on top of HTML which\n only accepts valid BCP 47 language tags, but who knows what atrocities are being preformed\n out there in the real world. So this attempts to emulate the other libraries.\n*/\nfunction parseAttr ( input, element, endToken ) {\n input = String( input );\n if ( !input || element === 'notextile' ) {\n return undefined;\n }\n\n let m;\n const st = {};\n const o = { 'style': st };\n let remaining = input;\n\n const isBlock = testBlock( element );\n const isImg = element === 'img';\n const isList = element === 'li';\n const isPhrase = !isBlock && !isImg && element !== 'a';\n const reAlign = ( isImg ) ? reAlignImg : reAlignBlock;\n\n do {\n if ( ( m = reStyles.exec( remaining ) ) ) {\n m[1].split( ';' ).forEach( function ( p ) {\n const d = p.match( reCSS );\n if ( d ) { st[ d[1] ] = d[2]; }\n });\n remaining = remaining.slice( m[0].length );\n continue;\n }\n\n if ( ( m = reLang.exec( remaining ) ) ) {\n const rm = remaining.slice( m[0].length );\n if ( ( !rm && isPhrase ) ||\n ( endToken && endToken === rm.slice( 0, endToken.length ) ) ) {\n m = null;\n }\n else {\n o['lang'] = m[1];\n remaining = remaining.slice( m[0].length );\n }\n continue;\n }\n\n if ( ( m = reClassid.exec( remaining ) ) ) {\n const rm = remaining.slice( m[0].length );\n if (\n ( !rm && isPhrase ) ||\n ( endToken && ( rm[0] === ' ' || endToken === rm.slice( 0, endToken.length ) ) )\n ) {\n m = null;\n }\n else {\n const bits = m[1].split( '#' );\n if ( bits[0] ) { o.class = bits[0]; }\n if ( bits[1] ) { o.id = bits[1]; }\n remaining = rm;\n }\n continue;\n }\n\n if ( isBlock || isList ) {\n if ( ( m = rePaddingL.exec( remaining ) ) ) {\n st[ 'padding-left' ] = `${ m[1].length }em`;\n remaining = remaining.slice( m[0].length );\n continue;\n }\n if ( ( m = rePaddingR.exec( remaining ) ) ) {\n st[ 'padding-right' ] = `${ m[1].length }em`;\n remaining = remaining.slice( m[0].length );\n continue;\n }\n }\n\n // only for blocks:\n if ( isImg || isBlock || isList ) {\n if ( ( m = reAlign.exec( remaining ) ) ) {\n const align = pbaAlignLookup[ m[1] ];\n if ( isImg ) {\n o[ 'align' ] = align;\n }\n else {\n st[ 'text-align' ] = align;\n }\n remaining = remaining.slice( m[0].length );\n continue;\n }\n }\n\n // only for table cells\n if ( element === 'td' || element === 'tr' ) {\n if ( ( m = reVAlign.exec( remaining ) ) ) {\n st[ 'vertical-align' ] = pbaVAlignLookup[ m[1] ];\n remaining = remaining.slice( m[0].length );\n continue;\n }\n }\n if ( element === 'td' ) {\n if ( ( m = reColSpan.exec( remaining ) ) ) {\n o[ 'colspan' ] = m[1];\n remaining = remaining.slice( m[0].length );\n continue;\n }\n if ( ( m = reRowSpan.exec( remaining ) ) ) {\n o[ 'rowspan' ] = m[1];\n remaining = remaining.slice( m[0].length );\n continue;\n }\n }\n }\n while ( m );\n\n // collapse styles\n const s = [];\n for ( const v in st ) {\n s.push( `${ v }:${ st[v] }` );\n }\n if ( s.length ) {\n o.style = s.join( ';' );\n }\n else {\n delete o.style;\n }\n\n return ( remaining === input ) ? undefined : [ input.length - remaining.length, o ];\n}\n\nmodule.exports = {\n copyAttr: copyAttr,\n parseAttr: parseAttr\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/attr.js\n **/","/* textile glyph parser */\n\nconst re = require( '../re' );\n\nconst reApostrophe = /(\\w)'(\\w)/g;\nconst reArrow = /([^\\-]|^)->/;\nconst reClosingDQuote = re.compile( /([^\\s\\[\\(])\"(?=$|\\s|[:punct:])/g );\nconst reClosingSQuote = re.compile( /([^\\s\\[\\(])'(?=$|\\s|[:punct:])/g );\nconst reCopyright = /(\\b ?|\\s|^)(?:\\(C\\)|\\[C\\])/gi;\nconst reDimsign = /([\\d\\.,]+['\"]? ?)x( ?)(?=[\\d\\.,]['\"]?)/g;\nconst reDoublePrime = re.compile( /(\\d*[\\.,]?\\d+)\"(?=\\s|$|[:punct:])/g );\nconst reEllipsis = /([^.]?)\\.{3}/g;\nconst reEmdash = /(^|[\\s\\w])--([\\s\\w]|$)/g;\nconst reEndash = / - /g;\nconst reOpenDQuote = /\"/g;\nconst reOpenSQuote = /'/g;\nconst reRegistered = /(\\b ?|\\s|^)(?:\\(R\\)|\\[R\\])/gi;\nconst reSinglePrime = re.compile( /(\\d*[\\.,]?\\d+)'(?=\\s|$|[:punct:])/g );\nconst reTrademark = /(\\b ?|\\s|^)(?:\\((?:TM|tm)\\)|\\[(?:TM|tm)\\])/g;\n\nexports.parseGlyph = function parseGlyph ( src ) {\n if ( typeof src !== 'string' ) {\n return src;\n }\n // NB: order is important here ...\n return src\n .replace( reArrow, '$1→' )\n .replace( reDimsign, '$1×$2' )\n .replace( reEllipsis, '$1…' )\n .replace( reEmdash, '$1—$2' )\n .replace( reEndash, ' – ' )\n .replace( reTrademark, '$1™' )\n .replace( reRegistered, '$1®' )\n .replace( reCopyright, '$1©' )\n // double quotes\n .replace( reDoublePrime, '$1″' )\n .replace( reClosingDQuote, '$1”' )\n .replace( reOpenDQuote, '“' )\n // single quotes\n .replace( reSinglePrime, '$1′' )\n .replace( reApostrophe, '$1’$2' )\n .replace( reClosingSQuote, '$1’' )\n .replace( reOpenSQuote, '‘' )\n // fractions and degrees\n .replace( /[\\(\\[]1\\/4[\\]\\)]/, '¼' )\n .replace( /[\\(\\[]1\\/2[\\]\\)]/, '½' )\n .replace( /[\\(\\[]3\\/4[\\]\\)]/, '¾' )\n .replace( /[\\(\\[]o[\\]\\)]/, '°' )\n .replace( /[\\(\\[]\\+\\/\\-[\\]\\)]/, '±' );\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/glyph.js\n **/","/* eslint camelcase: 0 */\n\nexports.txblocks = '(?:b[qc]|div|notextile|pre|h[1-6]|fn\\\\d+|p|###)';\n\nexports.ucaps = 'A-Z' +\n // Latin extended À-Þ\n '\\u00c0-\\u00d6\\u00d8-\\u00de' +\n // Latin caps with embelishments and ligatures...\n '\\u0100\\u0102\\u0104\\u0106\\u0108\\u010a\\u010c\\u010e\\u0110\\u0112\\u0114\\u0116\\u0118\\u011a\\u011c\\u011e\\u0120\\u0122\\u0124\\u0126\\u0128\\u012a\\u012c\\u012e\\u0130\\u0132\\u0134\\u0136\\u0139\\u013b\\u013d\\u013f' +\n '\\u0141\\u0143\\u0145\\u0147\\u014a\\u014c\\u014e\\u0150\\u0152\\u0154\\u0156\\u0158\\u015a\\u015c\\u015e\\u0160\\u0162\\u0164\\u0166\\u0168\\u016a\\u016c\\u016e\\u0170\\u0172\\u0174\\u0176\\u0178\\u0179\\u017b\\u017d' +\n '\\u0181\\u0182\\u0184\\u0186\\u0187\\u0189-\\u018b\\u018e-\\u0191\\u0193\\u0194\\u0196-\\u0198\\u019c\\u019d\\u019f\\u01a0\\u01a2\\u01a4\\u01a6\\u01a7\\u01a9\\u01ac\\u01ae\\u01af\\u01b1-\\u01b3\\u01b5\\u01b7\\u01b8\\u01bc' +\n '\\u01c4\\u01c7\\u01ca\\u01cd\\u01cf\\u01d1\\u01d3\\u01d5\\u01d7\\u01d9\\u01db\\u01de\\u01e0\\u01e2\\u01e4\\u01e6\\u01e8\\u01ea\\u01ec\\u01ee\\u01f1\\u01f4\\u01f6-\\u01f8\\u01fa\\u01fc\\u01fe' +\n '\\u0200\\u0202\\u0204\\u0206\\u0208\\u020a\\u020c\\u020e\\u0210\\u0212\\u0214\\u0216\\u0218\\u021a\\u021c\\u021e\\u0220\\u0222\\u0224\\u0226\\u0228\\u022a\\u022c\\u022e\\u0230\\u0232\\u023a\\u023b\\u023d\\u023e' +\n '\\u0241\\u0243-\\u0246\\u0248\\u024a\\u024c\\u024e' +\n '\\u1e00\\u1e02\\u1e04\\u1e06\\u1e08\\u1e0a\\u1e0c\\u1e0e\\u1e10\\u1e12\\u1e14\\u1e16\\u1e18\\u1e1a\\u1e1c\\u1e1e\\u1e20\\u1e22\\u1e24\\u1e26\\u1e28\\u1e2a\\u1e2c\\u1e2e\\u1e30\\u1e32\\u1e34\\u1e36\\u1e38\\u1e3a\\u1e3c\\u1e3e\\u1e40' +\n '\\u1e42\\u1e44\\u1e46\\u1e48\\u1e4a\\u1e4c\\u1e4e\\u1e50\\u1e52\\u1e54\\u1e56\\u1e58\\u1e5a\\u1e5c\\u1e5e\\u1e60\\u1e62\\u1e64\\u1e66\\u1e68\\u1e6a\\u1e6c\\u1e6e\\u1e70\\u1e72\\u1e74\\u1e76\\u1e78\\u1e7a\\u1e7c\\u1e7e' +\n '\\u1e80\\u1e82\\u1e84\\u1e86\\u1e88\\u1e8a\\u1e8c\\u1e8e\\u1e90\\u1e92\\u1e94\\u1e9e\\u1ea0\\u1ea2\\u1ea4\\u1ea6\\u1ea8\\u1eaa\\u1eac\\u1eae\\u1eb0\\u1eb2\\u1eb4\\u1eb6\\u1eb8\\u1eba\\u1ebc\\u1ebe' +\n '\\u1ec0\\u1ec2\\u1ec4\\u1ec6\\u1ec8\\u1eca\\u1ecc\\u1ece\\u1ed0\\u1ed2\\u1ed4\\u1ed6\\u1ed8\\u1eda\\u1edc\\u1ede\\u1ee0\\u1ee2\\u1ee4\\u1ee6\\u1ee8\\u1eea\\u1eec\\u1eee\\u1ef0\\u1ef2\\u1ef4\\u1ef6\\u1ef8\\u1efa\\u1efc\\u1efe' +\n '\\u2c60\\u2c62-\\u2c64\\u2c67\\u2c69\\u2c6b\\u2c6d-\\u2c70\\u2c72\\u2c75\\u2c7e\\u2c7f' +\n '\\ua722\\ua724\\ua726\\ua728\\ua72a\\ua72c\\ua72e\\ua732\\ua734\\ua736\\ua738\\ua73a\\ua73c\\ua73e' +\n '\\ua740\\ua742\\ua744\\ua746\\ua748\\ua74a\\ua74c\\ua74e\\ua750\\ua752\\ua754\\ua756\\ua758\\ua75a\\ua75c\\ua75e\\ua760\\ua762\\ua764\\ua766\\ua768\\ua76a\\ua76c\\ua76e\\ua779\\ua77b\\ua77d\\ua77e' +\n '\\ua780\\ua782\\ua784\\ua786\\ua78b\\ua78d\\ua790\\ua792\\ua7a0\\ua7a2\\ua7a4\\ua7a6\\ua7a8\\ua7aa';\n\nexports.txcite = ':((?:[^\\\\s()]|\\\\([^\\\\s()]+\\\\)|[()])+?)(?=[!-\\\\.:-@\\\\[\\\\\\\\\\\\]-`{-~]+(?:$|\\\\s)|$|\\\\s)';\n\nconst attr_class = exports.attr_class = '\\\\([^\\\\)]+\\\\)';\nconst attr_style = exports.attr_style = '\\\\{[^\\\\}]+\\\\}';\nconst attr_lang = exports.attr_lang = '\\\\[[^\\\\[\\\\]]+\\\\]';\nconst attr_align = exports.attr_align = '(?:<>|<|>|=)';\nconst attr_pad = exports.attr_pad = '[\\\\(\\\\)]+';\n\nconst txattr = exports.txattr = `(?:${ attr_class }|${ attr_style }|${ attr_lang }|${ attr_align }|${ attr_pad })*`;\n\nexports.txlisthd = `[\\\\t ]*[\\\\#\\\\*]*(\\\\*|\\\\#(?:_|\\\\d+)?)${ txattr }(?: \\\\S|\\\\.\\\\s*(?=\\\\S|\\\\n))`;\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/re_ext.js\n **/","/* textile list parser */\nconst ribbon = require( '../ribbon' );\nconst re = require( '../re' );\nconst merge = require( '../merge' );\n\nconst { parseAttr } = require( './attr' );\nconst { parsePhrase } = require( './phrase' );\n\nconst { txlisthd } = require( './re_ext' );\nre.pattern.txlisthd = txlisthd;\nconst reList = re.compile( /^((?:[:txlisthd:][^\\0]*?(?:\\r?\\n|$))+)(\\s*\\n|$)/, 's' );\nconst reItem = re.compile( /^([#\\*]+)([^\\0]+?)(\\n(?=[:txlisthd:])|$)/, 's' );\n\nfunction listPad ( n ) {\n let s = '\\n';\n while ( n-- ) {\n s += '\\t';\n }\n return s;\n}\n\nfunction testList ( src ) {\n return reList.exec( src );\n}\n\nfunction parseList ( src, options ) {\n src = ribbon( src.replace( /(^|\\r?\\n)[\\t ]+/, '$1' ) );\n\n const stack = [];\n const currIndex = {};\n const lastIndex = options._lst || {};\n let itemIndex = 0;\n let listAttr;\n let m;\n let n;\n let s;\n\n while ( ( m = reItem.exec( src ) ) ) {\n const item = [ 'li' ];\n const destLevel = m[1].length;\n const type = ( m[1].substr( -1 ) === '#' ) ? 'ol' : 'ul';\n let newLi = null;\n let lst;\n let par;\n let pba;\n let r;\n\n // list starts and continuations\n if ( ( n = /^(_|\\d+)/.exec( m[2] ) ) ) {\n itemIndex = isFinite( n[1] )\n ? parseInt( n[1], 10 )\n : lastIndex[ destLevel ] || currIndex[ destLevel ] || 1;\n m[2] = m[2].slice( n[1].length );\n }\n\n if ( ( pba = parseAttr( m[2], 'li' ) ) ) {\n m[2] = m[2].slice( pba[0] );\n pba = pba[1];\n }\n\n // list control\n if ( /^\\.\\s*$/.test( m[2] ) ) {\n listAttr = pba || {};\n src.advance( m[0] );\n continue;\n }\n\n // create nesting until we have correct level\n while ( stack.length < destLevel ) {\n // list always has an attribute object, this simplifies first-pba resolution\n lst = [ type, {}, listPad( stack.length + 1 ), ( newLi = [ 'li' ] ) ];\n par = stack[ stack.length - 1 ];\n if ( par ) {\n par.li.push( listPad( stack.length ) );\n par.li.push( lst );\n }\n stack.push({\n ul: lst,\n li: newLi,\n // count attributes's found per list\n att: 0\n });\n currIndex[ stack.length ] = 1;\n }\n\n // remove nesting until we have correct level\n while ( stack.length > destLevel ) {\n r = stack.pop();\n r.ul.push( listPad( stack.length ) );\n // lists have a predictable structure - move pba from listitem to list\n if ( r.att === 1 && !r.ul[3][1].substr ) {\n merge( r.ul[1], r.ul[3].splice( 1, 1 )[ 0 ] );\n }\n }\n\n // parent list\n par = stack[ stack.length - 1 ];\n\n if ( itemIndex ) {\n par.ul[1].start = itemIndex;\n currIndex[destLevel] = itemIndex;\n // falsy prevents this from fireing until it is set again\n itemIndex = 0;\n }\n if ( listAttr ) {\n // \"more than 1\" prevent attribute transfers on list close\n par.att = 9;\n merge( par.ul[1], listAttr );\n listAttr = null;\n }\n\n if ( !newLi ) {\n par.ul.push( listPad( stack.length ), item );\n par.li = item;\n }\n if ( pba ) {\n par.li.push( pba );\n par.att++;\n }\n Array.prototype.push.apply( par.li, parsePhrase( m[2].trim(), options ) );\n\n src.advance( m[0] );\n currIndex[destLevel] = ( currIndex[destLevel] || 0 ) + 1;\n }\n\n // remember indexes for continuations next time\n options._lst = currIndex;\n\n while ( stack.length ) {\n s = stack.pop();\n s.ul.push( listPad( stack.length ) );\n // lists have a predictable structure - move pba from listitem to list\n if ( s.att === 1 && !s.ul[3][1].substr ) {\n merge( s.ul[1], s.ul[3].splice( 1, 1 )[0] );\n }\n }\n\n return s.ul;\n}\n\nmodule.exports = {\n testList: testList,\n parseList: parseList\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/list.js\n **/","/* definitions list parser */\n\nconst ribbon = require( '../ribbon' );\n\nconst reDeflist = /^((?:- (?:[^\\n]\\n?)+?)+:=(?: *\\n[^\\0]+?=:(?:\\n|$)|(?:[^\\0]+?(?:$|\\n(?=\\n|- )))))+/;\nconst reItem = /^((?:- (?:[^\\n]\\n?)+?)+):=( *\\n[^\\0]+?=:\\s*(?:\\n|$)|(?:[^\\0]+?(?:$|\\n(?=\\n|- ))))/;\n\nfunction testDefList ( src ) {\n return reDeflist.exec( src );\n}\n\nfunction parseDefList ( src, options ) {\n src = ribbon( src.trim() );\n\n // late loading to get around the lack of non-circular-dependency support in RequireJS\n const parsePhrase = require( './phrase' ).parsePhrase;\n const parseFlow = require( './flow' ).parseFlow;\n\n const deflist = [ 'dl', '\\n' ];\n let terms;\n let def;\n let m;\n\n while ( ( m = reItem.exec( src ) ) ) {\n // add terms\n terms = m[1].split( /(?:^|\\n)\\- / ).slice( 1 );\n while ( terms.length ) {\n deflist.push( '\\t'\n , [ 'dt' ].concat( parsePhrase( terms.shift().trim(), options ) )\n , '\\n'\n );\n }\n // add definitions\n def = m[2].trim();\n deflist.push( '\\t'\n , [ 'dd' ].concat(\n ( /=:$/.test( def ) )\n ? parseFlow( def.slice( 0, -2 ).trim(), options )\n : parsePhrase( def, options )\n )\n , '\\n'\n );\n src.advance( m[0] );\n }\n return deflist;\n}\n\nexports.testDefList = testDefList;\nexports.parseDefList = parseDefList;\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/deflist.js\n **/","/* textile table parser */\n\nconst re = require( '../re' );\nconst merge = require( '../merge' );\nconst ribbon = require( '../ribbon' );\n\nconst { parseAttr } = require( './attr' );\nconst { parsePhrase } = require( './phrase' );\nconst { reIndent } = require( '../jsonml' );\n\nconst { txattr } = require( './re_ext' );\nre.pattern.txattr = txattr;\n\nconst reTable = re.compile( /^((?:table[:txattr:]\\.(?:\\s(.+?))\\s*\\n)?(?:(?:[:txattr:]\\.[^\\n\\S]*)?\\|.*?\\|[^\\n\\S]*(?:\\n|$))+)([^\\n\\S]*\\n)?/, 's' );\nconst reHead = /^table(_?)([^\\n]*?)\\.(?:[ \\t](.+?))?\\s*\\n/;\nconst reRow = re.compile( /^(?:\\|([~\\^\\-][:txattr:])\\.\\s*\\n)?([:txattr:]\\.[^\\n\\S]*)?\\|(.*?)\\|[^\\n\\S]*(\\n|$)/, 's' );\nconst reCaption = /^\\|=([^\\n+]*)\\n/;\nconst reColgroup = /^\\|:([^\\n+]*)\\|[\\r\\t ]*\\n/;\nconst reRowgroup = /^\\|([\\^\\-~])([^\\n+]*)\\.[ \\t\\r]*\\n/;\n\nconst charToTag = {\n '^': 'thead',\n '~': 'tfoot',\n '-': 'tbody'\n};\n\nfunction parseColgroup ( src ) {\n const colgroup = [ 'colgroup', {} ];\n src.split( '|' )\n .forEach( function ( s, isCol ) {\n const col = ( isCol ) ? {} : colgroup[ 1 ];\n let d = s.trim();\n let m;\n if ( d ) {\n if ( ( m = /^\\\\(\\d+)/.exec( d ) ) ) {\n col.span = +m[ 1 ];\n d = d.slice( m[ 0 ].length );\n }\n if ( ( m = parseAttr( d, 'col' ) ) ) {\n merge( col, m[ 1 ] );\n d = d.slice( m[ 0 ] );\n }\n if ( ( m = /\\b\\d+\\b/.exec( d ) ) ) {\n col.width = +m[0];\n }\n }\n if ( isCol ) {\n colgroup.push( '\\n\\t\\t', [ 'col', col ] );\n }\n });\n return colgroup.concat( [ '\\n\\t' ] );\n}\n\nfunction testTable ( src ) {\n return reTable.exec( src );\n}\n\nfunction parseTable ( src, options ) {\n src = ribbon( src.trim() );\n\n const rowgroups = [];\n let colgroup;\n let caption;\n const tAttr = {};\n let tCurr;\n let row;\n let inner;\n let pba;\n let more;\n let m;\n let extended = 0;\n\n const setRowGroup = function ( type, pba ) {\n tCurr = [ type, pba || {} ];\n rowgroups.push( tCurr );\n };\n\n if ( ( m = reHead.exec( src ) ) ) {\n // parse and apply table attr\n src.advance( m[0] );\n pba = parseAttr( m[2], 'table' );\n if ( pba ) {\n merge( tAttr, pba[1] );\n }\n if ( m[3] ) {\n tAttr.summary = m[3];\n }\n }\n\n // caption\n if ( ( m = reCaption.exec( src ) ) ) {\n caption = [ 'caption' ];\n if ( ( pba = parseAttr( m[1], 'caption' ) ) ) {\n caption.push( pba[1] );\n m[1] = m[1].slice( pba[0] );\n }\n if ( /\\./.test( m[1] ) ) { // mandatory \".\"\n caption.push( m[1].slice( 1 ).replace( /\\|\\s*$/, '' ).trim() );\n extended++;\n src.advance( m[0] );\n }\n else {\n caption = null;\n }\n }\n\n do {\n // colgroup\n if ( ( m = reColgroup.exec( src ) ) ) {\n colgroup = parseColgroup( m[1] );\n extended++;\n }\n // \"rowgroup\" (tbody, thead, tfoot)\n else if ( ( m = reRowgroup.exec( src ) ) ) {\n // PHP allows any amount of these in any order\n // and simply translates them straight through\n // the same is done here.\n const tag = charToTag[ m[1] ] || 'tbody';\n pba = parseAttr( `${ m[2] } `, tag );\n setRowGroup( tag, pba && pba[1] );\n extended++;\n }\n // row\n else if ( ( m = reRow.exec( src ) ) ) {\n if ( !tCurr ) { setRowGroup( 'tbody' ); }\n\n row = [ 'tr' ];\n\n if ( m[2] && ( pba = parseAttr( m[2], 'tr' ) ) ) {\n // FIXME: requires \"\\.\\s?\" -- else what ?\n row.push( pba[1] );\n }\n\n tCurr.push( '\\n\\t\\t', row );\n inner = ribbon( m[3] );\n\n do {\n inner.save();\n\n // cell loop\n const th = inner.startsWith( '_' );\n let cell = [ th ? 'th' : 'td' ];\n if ( th ) {\n inner.advance( 1 );\n }\n\n pba = parseAttr( inner, 'td' );\n if ( pba ) {\n inner.advance( pba[0] );\n cell.push( pba[1] ); // FIXME: don't do this if next text fails\n }\n\n if ( pba || th ) {\n const p = /^\\.\\s*/.exec( inner );\n if ( p ) {\n inner.advance( p[0] );\n }\n else {\n cell = [ 'td' ];\n inner.load();\n }\n }\n\n const mx = /^(==.*?==|[^\\|])*/.exec( inner );\n cell = cell.concat( parsePhrase( mx[0], options ) );\n row.push( '\\n\\t\\t\\t', cell );\n more = inner.valueOf().charAt( mx[0].length ) === '|';\n inner.advance( mx[0].length + 1 );\n }\n while ( more );\n\n row.push( '\\n\\t\\t' );\n }\n //\n if ( m ) {\n src.advance( m[0] );\n }\n }\n while ( m );\n\n // assemble table\n let table = [ 'table', tAttr ];\n if ( extended ) {\n if ( caption ) {\n table.push( '\\n\\t', caption );\n }\n if ( colgroup ) {\n table.push( '\\n\\t', colgroup );\n }\n rowgroups.forEach( function ( tbody ) {\n table.push( '\\n\\t', tbody.concat( [ '\\n\\t' ] ) );\n });\n }\n else {\n table = table.concat( reIndent( rowgroups[0].slice( 2 ), -1 ) );\n }\n\n table.push( '\\n' );\n return table;\n}\n\nmodule.exports = {\n parseColgroup: parseColgroup,\n parseTable: parseTable,\n testTable: testTable\n};\n\n\n\n/** WEBPACK FOOTER **\n ** ./src/textile/table.js\n **/"],"sourceRoot":""} \ No newline at end of file diff --git a/index.js b/index.js deleted file mode 100644 index 355a3d4..0000000 --- a/index.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./lib/textile'); diff --git a/lib/textile.js b/lib/textile.js deleted file mode 100644 index e2af69a..0000000 --- a/lib/textile.js +++ /dev/null @@ -1,1537 +0,0 @@ -/*** - * Textile parser for JavaScript - * - * Copyright (c) 2012 Borgar Þorsteinsson (MIT License). - * - */ -/*jshint - laxcomma:true - laxbreak:true - eqnull:true - loopfunc:true - sub:true -*/ -;(function(){ -"use strict"; - - /*** - * Regular Expression helper methods - * - * This provides the `re` object, which contains several helper - * methods for working with big regular expressions (soup). - * - */ - var re = { - _cache: {} - , pattern: { - 'punct': "[!-/:-@\\[\\\\\\]-`{-~]" - , 'space': '\\s' - } - , escape: function ( src ) { - return src.replace( /[\-\[\]\{\}\(\)\*\+\?\.\,\\\^\$\|\#\s]/g, "\\$&" ); - } - , collapse: function ( src ) { - return src.replace( /(?:#.*?(?:\n|$))/g, '' ) - .replace( /\s+/g, '' ) - ; - } - , expand_patterns: function ( src ) { - // TODO: provide escape for patterns: \[:pattern:] ? - return src.replace( /\[\:\s*(\w+)\s*\:\]/g, function ( m, k ) { - return ( k in re.pattern ) - ? re.expand_patterns( re.pattern[ k ] ) - : k - ; - }) - ; - } - , isRegExp: function ( r ) { - return Object.prototype.toString.call( r ) === "[object RegExp]"; - } - , compile: function ( src, flags ) { - if ( re.isRegExp( src ) ) { - if ( arguments.length === 1 ) { // no flags arg provided, use the RegExp one - flags = ( src.global ? 'g' : '' ) + - ( src.ignoreCase ? 'i' : '' ) + - ( src.multiline ? 'm' : '' ); - } - src = src.source; - } - // don't do the same thing twice - var ckey = src + ( flags || '' ); - if ( ckey in re._cache ) { return re._cache[ ckey ]; } - // allow classes - var rx = re.expand_patterns( src ); - // allow verbose expressions - if ( flags && /x/.test( flags ) ) { - rx = re.collapse( rx ); - } - // allow dotall expressions - if ( flags && /s/.test( flags ) ) { - rx = rx.replace( /([^\\])\./g, '$1[^\\0]' ); - } - // TODO: test if MSIE and add replace \s with [\s\u00a0] if it is? - // clean flags and output new regexp - flags = ( flags || '' ).replace( /[^gim]/g, '' ); - return ( re._cache[ ckey ] = new RegExp( rx, flags ) ); - } - }; - - - - - /*** - * JSONML helper methods - http://www.jsonml.org/ - * - * This provides the `JSONML` object, which contains helper - * methods for rendering JSONML to HTML. - * - * Note that the tag ! is taken to mean comment, this is however - * not specified in the JSONML spec. - * - */ - var JSONML = { - escape: function ( text, esc_quotes ) { - return text.replace( /&(?!(#\d{2,}|#x[\da-fA-F]{2,}|[a-zA-Z][a-zA-Z1-4]{1,6});)/g, "&" ) - .replace( //g, ">" ) - .replace( /"/g, esc_quotes ? """ : '"' ) - .replace( /'/g, esc_quotes ? "'" : "'" ) - ; - } - , toHTML: function ( jsonml ) { - - jsonml = jsonml.concat(); - - // basic case - if ( typeof jsonml === "string" ) { - return JSONML.escape( jsonml ); - } - - var tag = jsonml.shift() - , attributes = {} - , content = [] - , tag_attrs = "" - , a - ; - if ( jsonml.length && typeof jsonml[ 0 ] === "object" && !_isArray( jsonml[ 0 ] ) ) { - attributes = jsonml.shift(); - } - - while ( jsonml.length ) { - content.push( JSONML.toHTML( jsonml.shift() ) ); - } - - for ( a in attributes ) { - tag_attrs += ( attributes[ a ] == null ) - ? " " + a - : " " + a + '="' + JSONML.escape( String( attributes[ a ] ), true ) + '"' - ; - } - - // be careful about adding whitespace here for inline elements - if ( tag == "!" ) { - return ""; - } - else if ( tag in html_singletons ) { - return "<" + tag + tag_attrs + " />"; - } - else { - return "<" + tag + tag_attrs + ">" + content.join( "" ) + ""; - } - } - }; - - - // merge object b properties into obect a - function merge ( a, b ) { - if ( b ) { - for ( var k in b ) { - a[ k ] = b[ k ]; - } - } - return a; - } - - - var _isArray = Array.isArray || function ( a ) { return Object.prototype.toString.call(a) === '[object Array]'; }; - - /* expressions */ - re.pattern[ 'blocks' ] = '(?:b[qc]|div|notextile|pre|h[1-6]|fn\\d+|p|###)'; - re.pattern[ 'pba_class' ] = '\\([^\\)]+\\)'; - re.pattern[ 'pba_style' ] = '\\{[^\\}]+\\}'; - re.pattern[ 'pba_lang' ] = '\\[[^\\[\\]]+\\]'; - re.pattern[ 'pba_align' ] = '(?:<>|<|>|=)'; - re.pattern[ 'pba_pad' ] = '[\\(\\)]+'; - re.pattern[ 'pba_attr' ] = '(?:[:pba_class:]|[:pba_style:]|[:pba_lang:]|[:pba_align:]|[:pba_pad:])*'; - re.pattern[ 'url_punct' ] = '[.,«»″‹›!?]'; - re.pattern[ 'html_id' ] = '[a-zA-Z][a-zA-Z\\d:]*'; - re.pattern[ 'html_attr' ] = '(?:"[^"]+"|\'[^\']+\'|[^>\\s]+)'; - re.pattern[ 'tx_urlch' ] = '[\\w"$\\-_.+!*\'(),";\\/?:@=&%#{}|\\\\^~\\[\\]`]'; - re.pattern[ 'tx_cite' ] = ':((?:[^\\s()]|\\([^\\s()]+\\)|[()])+?)(?=[!-\\.:-@\\[\\\\\\]-`{-~]+(?:$|\\s)|$|\\s)'; - re.pattern[ 'listhd' ] = '[\\t ]*[\\#\\*]*(\\*|\\#(?:_|\\d+)?)[:pba_attr:](?: \\S|\\.\\s*(?=\\S|\\n))'; - re.pattern[ 'ucaps' ] = "A-Z"+ - // Latin extended À-Þ - "\u00c0-\u00d6\u00d8-\u00de"+ - // Latin caps with embelishments and ligatures... - "\u0100\u0102\u0104\u0106\u0108\u010a\u010c\u010e\u0110\u0112\u0114\u0116\u0118\u011a\u011c\u011e\u0120\u0122\u0124\u0126\u0128\u012a\u012c\u012e\u0130\u0132\u0134\u0136\u0139\u013b\u013d\u013f"+ - "\u0141\u0143\u0145\u0147\u014a\u014c\u014e\u0150\u0152\u0154\u0156\u0158\u015a\u015c\u015e\u0160\u0162\u0164\u0166\u0168\u016a\u016c\u016e\u0170\u0172\u0174\u0176\u0178\u0179\u017b\u017d"+ - "\u0181\u0182\u0184\u0186\u0187\u0189-\u018b\u018e-\u0191\u0193\u0194\u0196-\u0198\u019c\u019d\u019f\u01a0\u01a2\u01a4\u01a6\u01a7\u01a9\u01ac\u01ae\u01af\u01b1-\u01b3\u01b5\u01b7\u01b8\u01bc"+ - "\u01c4\u01c7\u01ca\u01cd\u01cf\u01d1\u01d3\u01d5\u01d7\u01d9\u01db\u01de\u01e0\u01e2\u01e4\u01e6\u01e8\u01ea\u01ec\u01ee\u01f1\u01f4\u01f6-\u01f8\u01fa\u01fc\u01fe"+ - "\u0200\u0202\u0204\u0206\u0208\u020a\u020c\u020e\u0210\u0212\u0214\u0216\u0218\u021a\u021c\u021e\u0220\u0222\u0224\u0226\u0228\u022a\u022c\u022e\u0230\u0232\u023a\u023b\u023d\u023e"+ - "\u0241\u0243-\u0246\u0248\u024a\u024c\u024e"+ - "\u1e00\u1e02\u1e04\u1e06\u1e08\u1e0a\u1e0c\u1e0e\u1e10\u1e12\u1e14\u1e16\u1e18\u1e1a\u1e1c\u1e1e\u1e20\u1e22\u1e24\u1e26\u1e28\u1e2a\u1e2c\u1e2e\u1e30\u1e32\u1e34\u1e36\u1e38\u1e3a\u1e3c\u1e3e\u1e40"+ - "\u1e42\u1e44\u1e46\u1e48\u1e4a\u1e4c\u1e4e\u1e50\u1e52\u1e54\u1e56\u1e58\u1e5a\u1e5c\u1e5e\u1e60\u1e62\u1e64\u1e66\u1e68\u1e6a\u1e6c\u1e6e\u1e70\u1e72\u1e74\u1e76\u1e78\u1e7a\u1e7c\u1e7e"+ - "\u1e80\u1e82\u1e84\u1e86\u1e88\u1e8a\u1e8c\u1e8e\u1e90\u1e92\u1e94\u1e9e\u1ea0\u1ea2\u1ea4\u1ea6\u1ea8\u1eaa\u1eac\u1eae\u1eb0\u1eb2\u1eb4\u1eb6\u1eb8\u1eba\u1ebc\u1ebe"+ - "\u1ec0\u1ec2\u1ec4\u1ec6\u1ec8\u1eca\u1ecc\u1ece\u1ed0\u1ed2\u1ed4\u1ed6\u1ed8\u1eda\u1edc\u1ede\u1ee0\u1ee2\u1ee4\u1ee6\u1ee8\u1eea\u1eec\u1eee\u1ef0\u1ef2\u1ef4\u1ef6\u1ef8\u1efa\u1efc\u1efe"+ - "\u2c60\u2c62-\u2c64\u2c67\u2c69\u2c6b\u2c6d-\u2c70\u2c72\u2c75\u2c7e\u2c7f"+ - "\ua722\ua724\ua726\ua728\ua72a\ua72c\ua72e\ua732\ua734\ua736\ua738\ua73a\ua73c\ua73e"+ - "\ua740\ua742\ua744\ua746\ua748\ua74a\ua74c\ua74e\ua750\ua752\ua754\ua756\ua758\ua75a\ua75c\ua75e\ua760\ua762\ua764\ua766\ua768\ua76a\ua76c\ua76e\ua779\ua77b\ua77d\ua77e"+ - "\ua780\ua782\ua784\ua786\ua78b\ua78d\ua790\ua792\ua7a0\ua7a2\ua7a4\ua7a6\ua7a8\ua7aa"; - - var re_block = re.compile( /^([:blocks:])/ ) - , re_block_se = re.compile( /^[:blocks:]$/ ) - , re_block_normal = re.compile( /^(.*?)($|\r?\n(?=[:listhd:])|\r?\n(?:\s*\n|$)+)/, 's' ) - , re_block_extended = re.compile( /^(.*?)($|\r?\n(?=[:listhd:])|\r?\n+(?=[:blocks:][:pba_attr:]\.))/, 's' ) - , re_ruler = /^(\-\-\-+|\*\*\*+|___+)(\r?\n\s+|$)/ - , re_list = re.compile( /^((?:[:listhd:][^\0]*?(?:\r?\n|$))+)(\s*\n|$)/,'s' ) - , re_list_item = re.compile( /^([\#\*]+)([^\0]+?)(\n(?=[:listhd:])|$)/, 's' ) - , re_deflist = /^((?:- (?:[^\n]\n?)+?)+:=(?: *\n[^\0]+?=:(?:\n|$)|(?:[^\0]+?(?:$|\n(?=\n|- )))))+/ - , re_deflist_item = /^((?:- (?:[^\n]\n?)+?)+):=( *\n[^\0]+?=:\s*(?:\n|$)|(?:[^\0]+?(?:$|\n(?=\n|- ))))/ - - , re_table = re.compile( /^((?:table[:pba_attr:]\.(?:\s(.+?))\s*\n)?(?:(?:[:pba_attr:]\.[^\n\S]*)?\|.*?\|[^\n\S]*(?:\n|$))+)([^\n\S]*\n)?/, 's' ) - , re_table_head = /^table(_?)([^\n]*?)\.(?:[ \t](.+?))?\s*\n/ - , re_table_row = re.compile( /^(?:\|([~\^\-][:pba_attr:])\.\s*\n)?([:pba_attr:]\.[^\n\S]*)?\|(.*?)\|[^\n\S]*(\n|$)/, 's' ) - , re_table_caption = /^\|=([^\n+]*)\n/ - , re_table_colgroup = /^\|:([^\n+]*)\|[\r\t ]*\n/ - , re_table_rowgroup = /^\|([\^\-\~])([^\n+]*)\.[ \t\r]*\n/ - - , re_fenced_phrase = /^\[(__?|\*\*?|\?\?|[\-\+\^~@%])([^\n]+)\1\]/ - , re_phrase = /^([\[\{]?)(__?|\*\*?|\?\?|[\-\+\^~@%])/ - , re_text = re.compile( /^.+?(?=[\\(\n*)/ ) - , re_html_tag = re.compile( /^<([:html_id:])((?:\s[^=\s\/]+(?:\s*=\s*[:html_attr:])?)+)?\s*(\/?)>(\n*)/ ) - , re_html_comment = re.compile( /^/, 's' ) - , re_html_end_tag = re.compile( /^<\/([:html_id:])([^>]*)>/ ) - , re_html_attr = re.compile( /^\s*([^=\s]+)(?:\s*=\s*("[^"]+"|'[^']+'|[^>\s]+))?/ ) - , re_entity = /&(#\d\d{2,}|#x[\da-fA-F]{2,}|[a-zA-Z][a-zA-Z1-4]{1,6});/ - - // glyphs - , re_dimsign = /([\d\.,]+['"]? ?)x( ?)(?=[\d\.,]['"]?)/g - , re_emdash = /(^|[\s\w])--([\s\w]|$)/g - , re_trademark = /(\b ?|\s|^)(?:\((?:TM|tm)\)|\[(?:TM|tm)\])/g - , re_registered = /(\b ?|\s|^)(?:\(R\)|\[R\])/gi - , re_copyright = /(\b ?|\s|^)(?:\(C\)|\[C\])/gi - , re_apostrophe = /(\w)\'(\w)/g - , re_double_prime = re.compile( /(\d*[\.,]?\d+)"(?=\s|$|[:punct:])/g ) - , re_single_prime = re.compile( /(\d*[\.,]?\d+)'(?=\s|$|[:punct:])/g ) - , re_closing_dquote = re.compile( /([^\s\[\(])"(?=$|\s|[:punct:])/g ) - , re_closing_squote = re.compile( /([^\s\[\(])'(?=$|\s|[:punct:])/g ) - - // pba - , re_pba_classid = /^\(([^\(\)\n]+)\)/ - , re_pba_padding_l = /^(\(+)/ - , re_pba_padding_r = /^(\)+)/ - , re_pba_align_blk = /^(<>|<|>|=)/ - , re_pba_align_img = /^(<|>|=)/ - , re_pba_valign = /^(~|\^|\-)/ - , re_pba_colspan = /^\\(\d+)/ - , re_pba_rowspan = /^\/(\d+)/ - , re_pba_styles = /^\{([^\}]*)\}/ - , re_pba_css = /^\s*([^:\s]+)\s*:\s*(.+)\s*$/ - , re_pba_lang = /^\[([^\[\]\n]+)\]/ - ; - - var phrase_convert = { - '*': 'strong' - , '**': 'b' - , '??': 'cite' - , '_': 'em' - , '__': 'i' - , '-': 'del' - , '%': 'span' - , '+': 'ins' - , '~': 'sub' - , '^': 'sup' - , '@': 'code' - }; - - // area, base, basefont, bgsound, br, col, command, embed, frame, hr, - // img, input, keygen, link, meta, param, source, track or wbr - var html_singletons = { - 'br': 1 - , 'hr': 1 - , 'img': 1 - , 'link': 1 - , 'meta': 1 - , 'wbr': 1 - , 'area': 1 - , 'param': 1 - , 'input': 1 - , 'option': 1 - , 'base': 1 - , 'col': 1 - }; - - var pba_align_lookup = { - '<': 'left' - , '=': 'center' - , '>': 'right' - , '<>': 'justify' - }; - - var pba_valign_lookup = { - '~':'bottom' - , '^':'top' - , '-':'middle' - }; - - // HTML tags allowed in the document (root) level that trigger HTML parsing - var allowed_blocktags = { - 'p': 0 - , 'hr': 0 - , 'ul': 1 - , 'ol': 0 - , 'li': 0 - , 'div': 1 - , 'pre': 0 - , 'object': 1 - , 'script': 0 - , 'noscript': 0 - , 'blockquote': 1 - , 'notextile': 1 - }; - - - function ribbon ( feed ) { - var _slot = null - , org = feed + '' - , pos = 0 - ; - return { - save: function () { - _slot = pos; - } - , load: function () { - pos = _slot; - feed = org.slice( pos ); - } - , advance: function ( n ) { - pos += ( typeof n === 'string' ) ? n.length : n; - return ( feed = org.slice( pos ) ); - } - , lookbehind: function ( nchars ) { - nchars = nchars == null ? 1 : nchars; - return org.slice( pos - nchars, pos ); - } - , startsWith: function ( s ) { - return feed.substring(0, s.length) === s; - } - , valueOf: function(){ - return feed; - } - , toString: function(){ - return feed; - } - }; - } - - - function builder ( arr ) { - var _arr = _isArray( arr ) ? arr : []; - return { - add: function ( node ) { - if ( typeof node === 'string' && - typeof _arr[_arr.length - 1 ] === 'string' ) { - // join if possible - _arr[ _arr.length - 1 ] += node; - } - else if ( _isArray( node ) ) { - var f = node.filter(function(s){ return s !== undefined; }); - _arr.push( f ); - } - else if ( node ) { - _arr.push( node ); - } - return this; - } - , merge: function ( s ) { - for (var i=0,l=s.length; i

    - user can still create nonsensical but "well-formed" markup - function parse_html ( src, whitelist_tags ) { - var org = src + '' - , list = [] - , root = list - , _stack = [] - , m - , oktag = whitelist_tags ? function ( tag ) { return tag in whitelist_tags; } : function () { return true; } - , tag - ; - src = (typeof src === 'string') ? ribbon( src ) : src; - // loop - do { - - if ( (m = re_html_comment.exec( src )) && oktag('!') ) { - src.advance( m[0] ); - list.push( [ '!', m[1] ] ); - } - - // end tag - else if ( (m = re_html_end_tag.exec( src )) && oktag(m[1]) ) { - tag = m[1]; - var junk = m[2]; - if ( _stack.length ) { - for (var i=_stack.length-1; i>=0; i--) { - var head = _stack[i]; - if ( head[0] === tag ) { - _stack.splice( i ); - list = _stack[ _stack.length - 1 ] || root; - break; - } - } - } - src.advance( m[0] ); - } - - // open/void tag - else if ( (m = re_html_tag.exec( src )) && oktag(m[1]) ) { - src.advance( m[0] ); - tag = m[1]; - var single = m[3] || m[1] in html_singletons - , tail = m[4] - , element = [ tag ] - ; - - // attributes - if ( m[2] ) { element.push( parse_html_attr( m[2] ) ); } - - // tag - if ( single ) { // single tag - // let us add the element and continue our quest... - list.push( element ); - if ( tail ) { list.push( tail ); } - } - else { // open tag - if ( tail ) { element.push( tail ); } - - // TODO: some things auto close other things: ,
  • ,

    , - // if ( tag === 'p' && _stack.length ) { - // var seek = /^(p)$/; - // for (var i=_stack.length-1; i>=0; i--) { - // var head = _stack[i]; - // if ( seek.test( head[0] ) /* === tag */ ) { - // //src.advance( m[0] ); - // _stack.splice( i ); - // list = _stack[i] || root; - // } - // } - // } - - // TODO: some elements can move parser into "text" mode - // style, xmp, iframe, noembed, noframe, textarea, title, script, noscript, plaintext - //if ( /^(script)$/.test( tag ) ) { } - - _stack.push( element ); - list.push( element ); - list = element; - - } - } - else { - - // no match, move by all "uninteresting" chars - m = /([^<]+|[^\0])/.exec( src ); - if ( m ) { - list.push( m[0] ); - } - src.advance( m ? m[0].length || 1 : 1 ); - - } - - } - while ( src.valueOf() ); - return root; - } - - /* attribute parser */ - - function parse_attr ( input, element, end_token ) { - /* - The attr bit causes massive problems for span elements when parentheses are used. - Parentheses are a total mess and, unsurprisingly, cause trip-ups: - - RC: `_{display:block}(span) span (span)_` -> `(span) span (span)` - PHP: `_{display:block}(span) span (span)_` -> `(span) span (span)` - - PHP and RC seem to mostly solve this by not parsing a final attr parens on spans if the - following character is a non-space. I've duplicated that: Class/ID is not matched on spans - if it is followed by `end_token` or . - - Lang is not matched here if it is followed by the end token. Theoretically I could limit the lang - attribute to /^\[[a-z]{2+}(\-[a-zA-Z0-9]+)*\]/ because Textile is layered on top of HTML which - only accepts valid BCP 47 language tags, but who knows what atrocities are being preformed - out there in the real world. So this attempts to emulate the other libraries. - */ - input += ''; - if ( !input || element === 'notextile' ) { return undefined; } - - var m - , st = {} - , o = { 'style': st } - , remaining = input - , is_block = /^(?:table|t[dh]|t(?:foot|head|body))$/.test( element ) || re_block_se.test( element ) // "in" test would be better but what about fn#.? - , is_img = element === 'img' - , is_list = element === 'li' - , is_phrase = !is_block && !is_img && element !== 'a' - , re_pba_align = ( is_img ) ? re_pba_align_img : re_pba_align_blk - ; - - do { - - if ( (m = re_pba_styles.exec( remaining )) ) { - m[1].split(';').forEach(function(p){ - var d = p.match( re_pba_css ); - if ( d ) { st[ d[1] ] = d[2]; } - }); - remaining = remaining.slice( m[0].length ); - continue; - } - - if ( (m = re_pba_lang.exec( remaining )) ) { - var rm = remaining.slice( m[0].length ); - if ( - ( !rm && is_phrase ) || - ( end_token && end_token === rm.slice(0,end_token.length) ) - ) { - m = null; - } - else { - o['lang'] = m[1]; - remaining = remaining.slice( m[0].length ); - } - continue; - } - - if ( (m = re_pba_classid.exec( remaining )) ) { - var rm = remaining.slice( m[0].length ); - if ( - ( !rm && is_phrase ) || - ( end_token && (rm[0] === ' ' || end_token === rm.slice(0,end_token.length)) ) - ) { - m = null; - } - else { - var bits = m[1].split( '#' ); - if ( bits[0] ) { o['class'] = bits[0]; } - if ( bits[1] ) { o['id'] = bits[1]; } - remaining = rm; - } - continue; - } - - if ( is_block || is_list ) { - if ( (m = re_pba_padding_l.exec( remaining )) ) { - st[ "padding-left" ] = ( m[1].length ) + "em"; - remaining = remaining.slice( m[0].length ); - continue; - } - if ( (m = re_pba_padding_r.exec( remaining )) ) { - st[ "padding-right" ] = ( m[1].length ) + "em"; - remaining = remaining.slice( m[0].length ); - continue; - } - } - - // only for blocks: - if ( is_img || is_block || is_list ) { - if ( (m = re_pba_align.exec( remaining )) ) { - var align = pba_align_lookup[ m[1] ]; - if ( is_img ) { - o[ 'align' ] = align; - } - else { - st[ 'text-align' ] = align; - } - remaining = remaining.slice( m[0].length ); - continue; - } - } - - // only for table cells - if ( element === 'td' || element === 'tr' ) { - if ( (m = re_pba_valign.exec( remaining )) ) { - st[ "vertical-align" ] = pba_valign_lookup[ m[1] ]; - remaining = remaining.slice( m[0].length ); - continue; - } - } - if ( element === 'td' ) { - if ( (m = re_pba_colspan.exec( remaining )) ) { - o[ "colspan" ] = m[1]; - remaining = remaining.slice( m[0].length ); - continue; - } - if ( (m = re_pba_rowspan.exec( remaining )) ) { - o[ "rowspan" ] = m[1]; - remaining = remaining.slice( m[0].length ); - continue; - } - } - - } - while ( m ); - - // collapse styles - var s = []; - for ( var v in st ) { s.push( v + ':' + st[v] ); } - if ( s.length ) { o.style = s.join(';'); } else { delete o.style; } - - return remaining == input - ? undefined - : [ input.length - remaining.length, o ] - ; - } - - - - /* glyph parser */ - - function parse_glyphs ( src ) { - if ( typeof src !== 'string' ) { return src; } - // NB: order is important here ... - return src - // arrow - .replace( /([^\-]|^)->/, '$1→' ) // arrow - // dimensions - .replace( re_dimsign, '$1×$2' ) // dimension sign - // ellipsis - .replace( /([^.]?)\.{3}/g, '$1…' ) // ellipsis - // dashes - .replace( re_emdash, '$1—$2' ) // em dash - .replace( / - /g, ' – ' ) // en dash - // legal marks - .replace( re_trademark, '$1™' ) // trademark - .replace( re_registered, '$1®' ) // registered - .replace( re_copyright, '$1©' ) // copyright - // double quotes - .replace( re_double_prime, '$1″' ) // double prime - .replace( re_closing_dquote, '$1”' ) // double closing quote - .replace( /"/g, '“' ) // double opening quote - // single quotes - .replace( re_single_prime, '$1′' ) // single prime - .replace( re_apostrophe, '$1’$2' ) // I'm an apostrophe - .replace( re_closing_squote, '$1’' ) // single closing quote - .replace( /'/g, '‘' ) - // fractions and degrees - .replace( /[\(\[]1\/4[\]\)]/, '¼' ) - .replace( /[\(\[]1\/2[\]\)]/, '½' ) - .replace( /[\(\[]3\/4[\]\)]/, '¾' ) - .replace( /[\(\[]o[\]\)]/, '°' ) - .replace( /[\(\[]\+\/\-[\]\)]/, '±' ) - ; - } - - - /* list parser */ - - function list_pad ( n ) { - var s = '\n'; - while ( n-- ) { s += '\t'; } - return s; - } - - function parse_list ( src, options ) { - src = ribbon( src.replace( /(^|\r?\n)[\t ]+/, '$1' ) ); - var stack = [] - , curr_idx = {} - , last_idx = options._lst || {} - , list_pba - , item_index = 0 - , m - , n - , s - ; - while ( (m = re_list_item.exec( src )) ) { - var item = [ 'li' ] - , start_index = 0 - , dest_level = m[1].length - , type = m[1].substr(-1) === '#' ? 'ol' : 'ul' - , new_li = null - , lst - , par - , pba - , r - ; - - // list starts and continuations - if ( n = /^(_|\d+)/.exec( m[2] ) ) { - item_index = isFinite( n[1] ) - ? parseInt( n[1], 10 ) - : last_idx[ dest_level ] || curr_idx[ dest_level ] || 1; - m[2] = m[2].slice( n[1].length ); - } - - if ( pba = parse_attr( m[2], 'li' ) ) { - m[2] = m[2].slice( pba[0] ); - pba = pba[1]; - } - - // list control - if ( /^\.\s*$/.test( m[2] ) ) { - list_pba = pba || {}; - src.advance( m[0] ); - continue; - } - - // create nesting until we have correct level - while ( stack.length < dest_level ) { - // list always has an attribute object, this simplifies first-pba resolution - lst = [ type, {}, list_pad( stack.length + 1 ), (new_li = [ 'li' ]) ]; - par = stack[ stack.length - 1 ]; - if ( par ) { - par.li.push( list_pad( stack.length ) ); - par.li.push( lst ); - } - stack.push({ - ul: lst - , li: new_li - , att: 0 // count pba's found per list - }); - curr_idx[ stack.length ] = 1; - } - - // remove nesting until we have correct level - while ( stack.length > dest_level ) { - r = stack.pop(); - r.ul.push( list_pad( stack.length ) ); - // lists have a predictable structure - move pba from listitem to list - if ( r.att === 1 && !r.ul[3][1].substr ) { - merge( r.ul[1], r.ul[3].splice( 1, 1 )[ 0 ] ); - } - } - - // parent list - par = stack[ stack.length - 1 ]; - - // have list_pba or start_index? - if ( item_index ) { - par.ul[1].start = curr_idx[ dest_level ] = item_index; - item_index = 0; // falsy prevents this from fireing until it is set again - } - if ( list_pba ) { - par.att = 9; // "more than 1" prevent pba transfers on list close - merge( par.ul[1], list_pba ); - list_pba = null; - } - - if ( !new_li ) { - par.ul.push( list_pad( stack.length ), item ); - par.li = item; - } - if ( pba ) { - par.li.push( pba ); - par.att++; - } - Array.prototype.push.apply( par.li, parse_inline( m[2].trim(), options ) ); - - src.advance( m[0] ); - curr_idx[ dest_level ] = (curr_idx[ dest_level ] || 0) + 1; - } - - // remember indexes for continuations next time - options._lst = curr_idx; - - while ( stack.length ) { - s = stack.pop(); - s.ul.push( list_pad( stack.length ) ); - // lists have a predictable structure - move pba from listitem to list - if ( s.att === 1 && !s.ul[3][1].substr ) { - merge( s.ul[1], s.ul[3].splice( 1, 1 )[ 0 ] ); - } - } - - return s.ul; - } - - - /* definitions list parser */ - - function parse_deflist ( src, options ) { - src = ribbon( src.trim() ); - var deflist = [ 'dl', '\n' ] - , terms - , def - , m - ; - while ( (m = re_deflist_item.exec( src )) ) { - // add terms - terms = m[1].split( /(?:^|\n)\- / ).slice(1); - while ( terms.length ) { - deflist.push( '\t' - , [ 'dt' ].concat( parse_inline( terms.shift().trim(), options ) ) - , '\n' - ); - } - // add definitions - def = m[2].trim(); - deflist.push( '\t' - , [ 'dd' ].concat( - /=:$/.test( def ) - ? parse_blocks( def.slice(0,-2).trim(), options ) - : parse_inline( def, options ) - ) - , '\n' - ); - src.advance( m[0] ); - } - return deflist; - } - - - /* table parser */ - - function parse_colgroup ( src ) { - var colgroup = [ 'colgroup', {} ]; - src.split( '|' ) - .forEach(function ( s, is_col ) { - var d = s.trim() - , col = ( is_col ) ? {} : colgroup[ 1 ] - , m; - if ( d ) { - if ( (m = /^\\(\d+)/.exec( d )) ) { - col.span = +m[ 1 ]; - d = d.slice( m[ 0 ].length ); - } - if ( (m = parse_attr( d, 'col' )) ) { - merge( col, m[ 1 ] ); - d = d.slice( m[ 0 ] ); - } - if ( (m = /\b\d+\b/.exec( d )) ) { - col.width = +m[0]; - } - } - if ( is_col ) { - colgroup.push( '\n\t\t', [ 'col', col ] ); - } - }); - return colgroup.concat([ '\n\t' ]); - } - - function parse_table ( src, options ) { - src = ribbon( src.trim() ); - var rowgroups = [] - , colgroup - , caption - , t_attr = {} - , t_curr - , row - , inner - , pba - , more - , m - , extended = 0 - ; - var set_rowgroup = function ( type, pba ) { - t_curr = [ type, pba || {} ]; - rowgroups.push( t_curr ); - }; - - if ( (m = re_table_head.exec( src )) ) { - // parse and apply table attr - src.advance( m[0] ); - pba = parse_attr( m[2], 'table' ); - if ( pba ) { - merge( t_attr, pba[1] ); - } - if ( m[3] ) { - t_attr.summary = m[3]; - } - } - - // caption - if ( (m = re_table_caption.exec( src )) ) { - caption = [ 'caption' ]; - if ( (pba = parse_attr( m[1], 'caption' )) ) { - caption.push( pba[1] ); - m[1] = m[1].slice( pba[0] ); - } - if ( /\./.test( m[1] ) ) { // mandatory "." - caption.push( m[1].slice( 1 ).replace( /\|\s*$/, '' ).trim() ); - extended++; - src.advance( m[0] ); - } - else { - caption = null; - } - } - - do { - // colgroup - if ( (m = re_table_colgroup.exec( src )) ) { - colgroup = parse_colgroup( m[1] ); - extended++; - } - // "rowgroup" (tbody, thead, tfoot) - else if ( (m = re_table_rowgroup.exec( src )) ) { - // PHP allows any amount of these in any order - // and simply translates them straight through - // the same is done here. - var tag = ( m[1] === '^' ) ? 'thead' : - ( m[1] === '~' ) ? 'tfoot' : - ( m[1] === '-' ) ? 'tbody' : 'tbody' ; - pba = parse_attr( m[2]+' ', tag ); - set_rowgroup( tag, pba && pba[1] ); - extended++; - } - // row - else if ( (m = re_table_row.exec( src )) ) { - if ( !t_curr ) { set_rowgroup( 'tbody' ); } - - row = [ 'tr' ]; - - if ( m[2] && (pba = parse_attr( m[2], 'tr' )) ) { - // FIXME: requires "\.\s?" -- else what ? - row.push( pba[1] ); - } - - t_curr.push( '\n\t\t', row ); - inner = ribbon( m[3] ); - - do { - inner.save(); - - // cell loop - var th = inner.startsWith( '_' ) - , cell = [ th ? 'th' : 'td' ] - ; - if ( th ) { - inner.advance( 1 ); - } - - pba = parse_attr( inner, 'td' ); - if ( pba ) { - inner.advance( pba[0] ); - cell.push( pba[1] ); // FIXME: don't do this if next text fails - } - - if ( pba || th ) { - var p = /^\.\s*/.exec( inner ); - if ( p ) { - inner.advance( p[0] ); - } - else { - cell = [ 'td' ]; - inner.load(); - } - } - - var mx = /^(==.*?==|[^\|])*/.exec( inner ); - cell = cell.concat( parse_inline( mx[0], options ) ); - row.push( '\n\t\t\t', cell ); - more = inner.valueOf().charAt( mx[0].length ) === '|'; - inner.advance( mx[0].length + 1 ); - - } - while ( more ); - - row.push( '\n\t\t' ); - - } - // - if ( m ) { - src.advance( m[0] ); - } - } while ( m ); - - // assemble table - var table = [ 'table', t_attr ]; - if ( extended ) { - if ( caption ) { - table.push( '\n\t', caption ) - } - if ( colgroup ) { - table.push( '\n\t', colgroup ) - } - rowgroups.forEach(function ( tbody ) { - table.push( '\n\t', tbody.concat([ '\n\t' ]) ); - }); - } - else { - table = table.concat( reindent( rowgroups[0].slice(2), -1 ) ); - } - - table.push( '\n' ); - return table; - - } - - - /* inline parser */ - - function parse_inline ( src, options ) { - - src = ribbon( src ); - var list = builder() - , m - , pba - ; - - // loop - do { - src.save(); - - // linebreak -- having this first keeps it from messing to much with other phrases - if ( src.startsWith( '\r\n' ) ) { - src.advance( 1 ); // skip cartridge returns - } - if ( src.startsWith( '\n' ) ) { - src.advance( 1 ); - - if ( options.breaks ) { - list.add( [ 'br' ] ); - } - list.add( '\n' ); - continue; - } - - // inline notextile - if ( (m = /^==(.*?)==/.exec( src )) ) { - src.advance( m[0] ); - list.add( m[1] ); - continue; - } - - // lookbehind => /([\s>.,"'?!;:])$/ - var behind = src.lookbehind( 1 ); - var boundary = !behind || /^[\s>.,"'?!;:()]$/.test( behind ); - // FIXME: need to test right boundary for phrases as well - if ( (m = re_phrase.exec( src )) && ( boundary || m[1] ) ) { - src.advance( m[0] ); - var tok = m[2] - , fence = m[1] - , phrase_type = phrase_convert[ tok ] - , code = phrase_type === 'code' - ; - if ( (pba = !code && parse_attr( src, phrase_type, tok )) ) { - src.advance( pba[0] ); - pba = pba[1]; - } - // FIXME: if we can't match the fence on the end, we should output fence-prefix as normal text - // seek end - var m_mid; - var m_end; - if ( fence === '[' ) { - m_mid = '^(.*?)'; - m_end = '(?:])'; - } - else if ( fence === '{' ) { - m_mid = '^(.*?)'; - m_end = '(?:})'; - } - else { - var t1 = re.escape( tok.charAt(0) ); - m_mid = ( code ) - ? '^(\\S+|\\S+.*?\\S)' - : '^([^\\s' + t1 + ']+|[^\\s' + t1 + '].*?\\S('+t1+'*))' - ; - m_end = '(?=$|[\\s.,"\'!?;:()«»„“”‚‘’])'; - } - var rx = re.compile( m_mid + '(' + re.escape( tok ) + ')' + m_end ); - if ( (m = rx.exec( src )) && m[1] ) { - src.advance( m[0] ); - if ( code ) { - list.add( [ phrase_type, m[1] ] ); - } - else { - list.add( [ phrase_type, pba ].concat( parse_inline( m[1], options ) ) ); - } - continue; - } - // else - src.load(); - } - - // image - if ( (m = re_image.exec( src )) || (m = re_image_fenced.exec( src )) ) { - src.advance( m[0] ); - - pba = m[1] && parse_attr( m[1], 'img' ); - var attr = pba ? pba[1] : { 'src':'' } - , img = [ 'img', attr ] - ; - attr.src = m[2]; - attr.alt = m[3] ? ( attr.title = m[3] ) : ''; - - if ( m[4] ) { // +cite causes image to be wraped with a link (or link_ref)? - // TODO: support link_ref for image cite - img = [ 'a', { 'href': m[4] }, img ]; - } - list.add( img ); - continue; - } - - // html comment - if ( (m = re_html_comment.exec( src )) ) { - src.advance( m[0] ); - list.add( [ '!', m[1] ] ); - continue; - } - // html tag - // TODO: this seems to have a lot of overlap with block tags... DRY? - if ( (m = re_html_tag.exec( src )) ) { - src.advance( m[0] ); - var tag = m[1] - , single = m[3] || m[1] in html_singletons - , element = [ tag ] - , tail = m[4] - ; - if ( m[2] ) { - element.push( parse_html_attr( m[2] ) ); - } - if ( single ) { // single tag - list.add( element ).add( tail ); - continue; - } - else { // need terminator - // gulp up the rest of this block... - var re_end_tag = re.compile( "^(.*?)()", 's' ); - if ( (m = re_end_tag.exec( src )) ) { - src.advance( m[0] ); - if ( tag === 'code' ) { - element.push( tail, m[1] ); - } - else if ( tag === 'notextile' ) { - list.merge( parse_inline( m[1], options ) ); - continue; - } - else { - element = element.concat( parse_inline( m[1], options ) ); - } - list.add( element ); - continue; - } - // end tag is missing, treat tag as normal text... - } - src.load(); - } - - // footnote - if ( (m = re_footnote.exec( src )) && /\S/.test( behind ) ) { - src.advance( m[0] ); - list.add( [ 'sup', { 'class': 'footnote', 'id': 'fnr' + m[1] }, - ( m[2] === '!' ? m[1] // "!" suppresses the link - : [ 'a', { href: '#fn' + m[1] }, m[1] ] ) - ] ); - continue; - } - - // caps / abbr - if ( (m = re_caps.exec( src )) ) { - src.advance( m[0] ); - var caps = [ 'span', { 'class': 'caps' }, m[1] ]; - if ( m[2] ) { - caps = [ 'acronym', { 'title': m[2] }, caps ]; // FIXME: use , not acronym! - } - list.add( caps ); - continue; - } - - // links - if ( (boundary && (m = re_link.exec( src ))) || (m = re_link_fenced.exec( src )) ) { - src.advance( m[0] ); - var title = m[1].match( re_link_title ) - , inner = ( title ) ? m[1].slice( 0, m[1].length - title[0].length ) : m[1] - ; - if ( (pba = parse_attr( inner, 'a' )) ) { - inner = inner.slice( pba[0] ); - pba = pba[1]; - } - else { - pba = {}; - } - if ( title && !inner ) { inner = title[0]; title = ""; } - pba.href = m[2]; - if ( title ) { pba.title = title[1]; } - list.add( [ 'a', pba ].concat( parse_inline( inner.replace( /^(\.?\s*)/, '' ), options ) ) ); - continue; - } - - // no match, move by all "uninteresting" chars - m = /([a-zA-Z0-9,.':]+|[ \f\r\t\v\xA0\u2028\u2029]+|[^\0])/.exec( src ); - if ( m ) { - list.add( m[0] ); - } - src.advance( m ? m[0].length || 1 : 1 ); - - } - while ( src.valueOf() ); - - return list.get().map( parse_glyphs ); - } - - - /* block parser */ - - function parse_blocks ( src, options ) { - - var list = builder() - , paragraph = function ( s, tag, pba, linebreak ) { - tag = tag || 'p'; - var out = []; - s.split( /(?:\r?\n){2,}/ ).forEach(function( bit, i ) { - if ( tag === 'p' && /^\s/.test( bit ) ) { - // no-paragraphs - // WTF?: Why does Textile not allow linebreaks in spaced lines - bit = bit.replace( /\r?\n[\t ]/g, ' ' ).trim(); - out = out.concat( parse_inline( bit, options ) ); - } - else { - if ( linebreak && i ) { out.push( linebreak ); } - out.push( pba ? [ tag, pba ].concat( parse_inline( bit, options ) ) - : [ tag ].concat( parse_inline( bit, options ) ) ); - } - }); - return out; - } - , link_refs = {} - , m - ; - src = ribbon( src.replace( /^( *\r?\n)+/, '' ) ); - - // loop - while ( src.valueOf() ) { - src.save(); - - // link_ref -- this goes first because it shouldn't trigger a linebreak - if ( (m = re_link_ref.exec( src )) ) { - src.advance( m[0] ); - link_refs[ m[1] ] = m[2]; - continue; - } - - // add linebreak - list.linebreak(); - - // named block - if ( (m = re_block.exec( src )) ) { - src.advance( m[0] ); - var block_type = m[0] - , pba = parse_attr( src, block_type ) - ; - if ( pba ) { - src.advance( pba[0] ); - pba = pba[1]; - } - if ( (m = /^\.(\.?)(?:\s|(?=:))/.exec( src )) ) { - // FIXME: this whole copy_pba seems rather strange? - // slurp rest of block - var extended = !!m[1]; - m = ( extended ? re_block_extended : re_block_normal ).exec( src.advance( m[0] ) ); - src.advance( m[0] ); - // bq | bc | notextile | pre | h# | fn# | p | ### - if ( block_type === 'bq' ) { - var cite, inner = m[1]; - if ( (m = /^:(\S+)\s+/.exec( inner )) ) { - if ( !pba ) { pba = {}; } - pba.cite = m[1]; - inner = inner.slice( m[0].length ); - } - // RedCloth adds all attr to both: this is bad because it produces duplicate IDs - list.add( [ 'blockquote', pba, '\n' ].concat( - paragraph( inner, 'p', copy_pba(pba, { 'cite':1, 'id':1 }), '\n' ) - ).concat(['\n']) ); - } - else if ( block_type === 'bc' ) { - var sub_pba = ( pba ) ? copy_pba(pba, { 'id':1 }) : null; - list.add( [ 'pre', pba, ( sub_pba ? [ 'code', sub_pba, m[1] ] : [ 'code', m[1] ] ) ] ); - } - else if ( block_type === 'notextile' ) { - list.merge( parse_html( m[1] ) ); - } - else if ( block_type === '###' ) { - // ignore the insides - } - else if ( block_type === 'pre' ) { - // I disagree with RedCloth, but agree with PHP here: - // "pre(foo#bar).. line1\n\nline2" prevents multiline preformat blocks - // ...which seems like the whole point of having an extended pre block? - list.add( [ 'pre', pba, m[1] ] ); - } - else if ( re_footnote_def.test( block_type ) ) { // footnote - // Need to be careful: RedCloth fails "fn1(foo#m). footnote" -- it confuses the ID - var fnid = block_type.replace( /\D+/g, '' ); - if ( !pba ) { pba = {}; } - pba['class'] = ( pba['class'] ? pba['class'] + ' ' : '' ) + 'footnote'; - pba['id'] = 'fn' + fnid; - list.add( [ "p", pba, [ 'a', { 'href': '#fnr' + fnid }, [ 'sup', fnid ] ], ' ' ].concat( parse_inline( m[1], options ) ) ); - } - else { // heading | paragraph - list.merge( paragraph( m[1], block_type, pba, '\n' ) ); - } - continue; - } - else { - src.load(); - } - } - - // HTML comment - if ( (m = re_html_comment.exec( src )) ) { - src.advance( m[0] + (/(?:\s*\n+)+/.exec( src ) || [])[0] ); - list.add( [ '!', m[1] ] ); - continue; - } - - // block HTML - if ( (m = re_html_tag_block.exec( src )) ) { - var tag = m[1] - , single = m[3] || tag in html_singletons - , tail = m[4] - ; - // Unsurprisingly, all Textile implementations I have tested have trouble parsing simple HTML: - // - // "
    a\n
    b\n
    c\n
    d" - // - // I simply match them here as there is no way anyone is using nested HTML today, or if they - // are, then this will at least output less broken HTML as redundant tags will get quoted. - - // Is block tag? ... - if ( tag in allowed_blocktags ) { - src.advance( m[0] ); - - var element = [ tag ]; - - if ( m[2] ) { - element.push( parse_html_attr( m[2] ) ); - } - - if ( single ) { // single tag - // let us add the element and continue our quest... - list.add( element ); - continue; - } - else { // block - - // gulp up the rest of this block... - var re_end_tag = re.compile( "^(.*?)(\\s*)()(\\s*)", 's' ); - if ( (m = re_end_tag.exec( src )) ) { - src.advance( m[0] ); - if ( tag === 'pre' ) { - element.push( tail ); - element = element.concat( parse_html( m[1].replace( /(\r?\n)+$/, '' ), { 'code': 1 } ) ); - if ( m[2] ) { element.push( m[2] ); } - list.add( element ); - } - else if ( tag === 'notextile' ) { - element = parse_html( m[1].trim() ); - list.merge( element ); - } - else if ( tag === 'script' || tag === 'noscript' ) { - //element = parse_html( m[1].trim() ); - element.push( tail + m[1] ); - list.add( element ); - } - else { - // These strange (and unnecessary) linebreak tests are here to get the - // tests working perfectly. In reality, this doesn't matter one bit. - if ( /\n/.test( tail ) ) { element.push( '\n' ); } - if ( /\n/.test( m[1] ) ) { - element = element.concat( parse_blocks( m[1], options ) ); - } - else { - element = element.concat( parse_inline( m[1].replace( /^ +/, '' ), options ) ); - } - if ( /\n/.test( m[2] ) ) { element.push( '\n' ); } - - list.add( element ); - } - continue; - } - /*else { - // end tag is missing, treat tag as normal text... - }*/ - } - } - src.load(); - } - - // ruler - if ( (m = re_ruler.exec( src )) ) { - src.advance( m[0] ); - list.add( [ 'hr' ] ); - continue; - } - - // list - if ( (m = re_list.exec( src )) ) { - src.advance( m[0] ); - list.add( parse_list( m[0], options ) ); - continue; - } - - // definition list - if ( (m = re_deflist.exec( src )) ) { - src.advance( m[0] ); - list.add( parse_deflist( m[0], options ) ); - continue; - } - - // table - if ( (m = re_table.exec( src )) ) { - src.advance( m[0] ); - list.add( parse_table( m[1], options ) ); - continue; - } - - // paragraph - m = re_block_normal.exec( src ); - list.merge( paragraph( m[1], 'p', undefined, "\n" ) ); - src.advance( m[0] ); - - } - - return list.get().map( fix_links, link_refs ); - } - - - // recurse the tree and swap out any "href" attributes - function fix_links ( jsonml ) { - if ( _isArray( jsonml ) ) { - if ( jsonml[0] === 'a' ) { // found a link - var attr = jsonml[1]; - if ( typeof attr === "object" && 'href' in attr && attr.href in this ) { - attr.href = this[ attr.href ]; - } - } - for (var i=1,l=jsonml.length; i by default - }; - textile.setOptions = textile.setoptions = function ( opt ) { - merge( textile.defaults, opt ); - return this; - }; - - - textile.parse = textile.convert = textile; - textile.html_parser = parse_html; - textile.jsonml = function ( txt, opt ) { - // get a throw-away copy of options - opt = merge( merge( {}, textile.defaults ), opt || {} ); - // parse and return tree - return [ 'html' ].concat( parse_blocks( txt, opt ) ); - }; - textile.serialize = JSONML.toHTML; - - if ( typeof module !== 'undefined' && module.exports ) { - module.exports = textile; - } - else { - this.textile = textile; - } - - -}).call(function() { - return this || (typeof window !== 'undefined' ? window : global); -}()); diff --git a/package.json b/package.json index fc8e7b2..8a8e3e5 100644 --- a/package.json +++ b/package.json @@ -2,8 +2,13 @@ "name": "textile-js", "description": "A full-featured JavaScript Textile parser", "author": "Borgar Þorsteinsson ", - "version": "1.1.1", - "main": "./lib/textile.js", + "version": "2.0.0", + "scripts": { + "build": "webpack && WEBPACK_ENV=min webpack", + "dev": "webpack --progress --watch", + "test": "ava | tnyan" + }, + "main": "./dist/textile.js", "bin": "./bin/textile", "preferGlobal": false, "repository": "git://github.com/borgar/textile-js.git", @@ -11,5 +16,32 @@ "bugs": { "url": "http://github.com/borgar/textile-js/issues" }, "keywords": [ "textile", "markup", "html" ], "tags": [ "textile", "markup", "html" ], - "license": "MIT" + "license": "MIT", + "ava": { + "files": [ + "test/*.js", + "!**/instiki.js", + "!**/code.js", + "!**/html.js" + ], + "source": [ + "src/**/*.js" + ], + "tap": true, + "failFast": true + }, + "devDependencies": { + "ava": "^0.14.0", + "babel": "^6.5.2", + "babel-core": "^6.8.0", + "babel-loader": "^6.2.4", + "babel-plugin-add-module-exports": "^0.2.0", + "babel-preset-es2015": "^6.6.0", + "babel-preset-es2015-node6": "^0.2.0", + "eslint": "^2.9.0", + "eslint-loader": "^1.3.0", + "eslint-plugin-promise": "^1.1.0", + "tap-nyan": "0.0.2", + "webpack": "^1.13.0" + } } diff --git a/src/builder.js b/src/builder.js new file mode 100644 index 0000000..1506501 --- /dev/null +++ b/src/builder.js @@ -0,0 +1,37 @@ +module.exports = function builder ( initArr ) { + const arr = Array.isArray( initArr ) ? initArr : []; + + return { + add: function ( node ) { + if ( typeof node === 'string' && + typeof arr[ arr.length - 1 ] === 'string' ) { + // join if possible + arr[ arr.length - 1 ] += node; + } + else if ( Array.isArray( node ) ) { + arr.push( node.filter( s => s !== undefined ) ); + } + else if ( node ) { + arr.push( node ); + } + return this; + }, + + merge: function ( arr ) { + for ( let i = 0, l = arr.length; i < l; i++ ) { + this.add( arr[i] ); + } + return this; + }, + + linebreak: function () { + if ( arr.length ) { + this.add( '\n' ); + } + }, + + get: function () { + return arr; + } + }; +}; diff --git a/src/fixlinks.js b/src/fixlinks.js new file mode 100644 index 0000000..fde4267 --- /dev/null +++ b/src/fixlinks.js @@ -0,0 +1,18 @@ +// recurse the tree and swap out any "href" attributes +// this uses the context as the replace dictionary so it can be fed to Array#map +module.exports = function fixLinks ( ml, dict ) { + if ( Array.isArray( ml ) ) { + if ( ml[0] === 'a' ) { // found a link + const attr = ml[1]; + if ( typeof attr === 'object' && 'href' in attr && attr.href in dict ) { + attr.href = dict[attr.href]; + } + } + for ( let i = 0, l = ml.length; i < l; i++ ) { + if ( Array.isArray( ml[i] ) ) { + fixLinks( ml[i], dict ); + } + } + } + return ml; +}; diff --git a/src/html.js b/src/html.js new file mode 100644 index 0000000..49b3e40 --- /dev/null +++ b/src/html.js @@ -0,0 +1,168 @@ +const re = require( './re' ); +const ribbon = require( './ribbon' ); + +re.pattern.html_id = '[a-zA-Z][a-zA-Z\\d:]*'; +re.pattern.html_attr = '(?:"[^"]+"|\'[^\']+\'|[^>\\s]+)'; + +const reAttr = re.compile( /^\s*([^=\s]+)(?:\s*=\s*("[^"]+"|'[^']+'|[^>\s]+))?/ ); +const reComment = re.compile( /^/, 's' ); +const reEndTag = re.compile( /^<\/([:html_id:])([^>]*)>/ ); +const reTag = re.compile( /^<([:html_id:])((?:\s[^=\s\/]+(?:\s*=\s*[:html_attr:])?)+)?\s*(\/?)>(\n*)/ ); +const reHtmlTagBlock = re.compile( /^\s*<([:html_id:](?::[a-zA-Z\d]+)*)((?:\s[^=\s\/]+(?:\s*=\s*[:html_attr:])?)+)?\s*(\/?)>(\n*)/ ); + +// area, base, basefont, bgsound, br, col, command, embed, frame, hr, +// img, input, keygen, link, meta, param, source, track or wbr +const singletons = { + br: 1, + hr: 1, + img: 1, + link: 1, + meta: 1, + wbr: 1, + area: 1, + param: 1, + input: 1, + option: 1, + base: 1, + col: 1 +}; + +function allowAll () { + return true; +} + +function testComment ( src ) { + return reComment.exec( src ); +} + +function testOpenTagBlock ( src ) { + return reHtmlTagBlock.exec( src ); +} + +function testOpenTag ( src ) { + return reTag.exec( src ); +} + +function testCloseTag ( src ) { + return reEndTag.exec( src ); +} + +function parseHtmlAttr ( attrSrc ) { + // parse ATTR and add to element + const attr = {}; + let m; + while ( ( m = reAttr.exec( attrSrc ) ) ) { + attr[ m[1] ] = ( typeof m[2] === 'string' ) ? m[2].replace( /^(["'])(.*)\1$/, '$2' ) : null; + attrSrc = attrSrc.slice( m[0].length ); + } + return attr; +} + +// This "indesciminately" parses HTML text into a list of JSON-ML element +// No steps are taken however to prevent things like

    - user can still create nonsensical but "well-formed" markup +function parseHtml ( src, whitelistTags ) { + const root = []; + let list = root; + const _stack = []; + const oktag = whitelistTags ? function ( tag ) { return tag in whitelistTags; } : allowAll; + let m; + let tag; + + src = ( typeof src === 'string' ) ? ribbon( src ) : src; + // loop + do { + // comment + if ( ( m = testComment( src ) ) && oktag( '!' ) ) { + src.advance( m[0] ); + list.push( [ '!', m[1] ] ); + } + + // end tag + else if ( ( m = testCloseTag( src ) ) && oktag( m[1] ) ) { + tag = m[1]; + if ( _stack.length ) { + for ( let i = _stack.length - 1; i >= 0; i-- ) { + const head = _stack[i]; + if ( head[0] === tag ) { + _stack.splice( i ); + list = _stack[_stack.length - 1] || root; + break; + } + } + } + src.advance( m[0] ); + } + + // open/void tag + else if ( ( m = testOpenTag( src ) ) && oktag( m[1] ) ) { + src.advance( m[0] ); + tag = m[1]; + const single = m[3] || m[1] in singletons; + const tail = m[4]; + const element = [ tag ]; + + // attributes + if ( m[2] ) { + element.push( parseHtmlAttr( m[2] ) ); + } + + // single tag + if ( single ) { + // let us add the element and continue our quest... + list.push( element ); + if ( tail ) { + list.push( tail ); + } + } + // open tag + else { + if ( tail ) { + element.push( tail ); + } + + // TODO: some things auto close other things: ,
  • ,

    , + // if ( tag === 'p' && _stack.length ) { + // var seek = /^(p)$/; + // for (var i=_stack.length-1; i>=0; i--) { + // var head = _stack[i]; + // if ( seek.test( head[0] ) /* === tag */ ) { + // //src.advance( m[0] ); + // _stack.splice( i ); + // list = _stack[i] || root; + // } + // } + // } + + // TODO: some elements can move parser into "text" mode + // style, xmp, iframe, noembed, noframe, textarea, title, script, noscript, plaintext + // if ( /^(script)$/.test( tag ) ) { } + + _stack.push( element ); + list.push( element ); + list = element; + } + } + // text content + else { + // no match, move by all "uninteresting" chars + m = /([^<]+|[^\0])/.exec( src ); + if ( m ) { + list.push( m[0] ); + } + src.advance( m ? m[0].length || 1 : 1 ); + } + } + while ( src.valueOf() ); + + return root; +} + +module.exports = { + singletons: singletons, + parseHtml: parseHtml, + parseHtmlAttr: parseHtmlAttr, + testCloseTag: testCloseTag, + testOpenTagBlock: testOpenTagBlock, + testOpenTag: testOpenTag, + testComment: testComment +}; diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..64ae6cf --- /dev/null +++ b/src/index.js @@ -0,0 +1,40 @@ +/* +** Textile parser for JavaScript +** +** Copyright (c) 2012 Borgar Þorsteinsson (MIT License). +** +*/ + +const merge = require( './merge' ); +const { toHTML } = require( './jsonml' ); +const { parseFlow } = require( './textile/flow' ); +const { parseHtml } = require( './html' ); + +function textile ( txt, opt ) { + // get a throw-away copy of options + opt = merge( merge({}, textile.defaults ), opt || {}); + // run the converter + return parseFlow( txt, opt ).map( toHTML ).join( '' ); +}; +module.exports = textile; + +// options +textile.defaults = { + // single-line linebreaks are converted to
    by default + 'breaks': true +}; +textile.setOptions = textile.setoptions = function ( opt ) { + merge( textile.defaults, opt ); + return this; +}; + +textile.parse = textile.convert = textile; +textile.html_parser = parseHtml; + +textile.jsonml = function ( txt, opt ) { + // get a throw-away copy of options + opt = merge( merge({}, textile.defaults ), opt || {}); + // parse and return tree + return [ 'html' ].concat( parseFlow( txt, opt ) ); +}; +textile.serialize = toHTML; diff --git a/src/jsonml.js b/src/jsonml.js new file mode 100644 index 0000000..90c32e9 --- /dev/null +++ b/src/jsonml.js @@ -0,0 +1,88 @@ +/* +** JSONML helper methods - http://www.jsonml.org/ +** +** This provides the `JSONML` object, which contains helper +** methods for rendering JSONML to HTML. +** +** Note that the tag ! is taken to mean comment, this is however +** not specified in the JSONML spec. +*/ + +const singletons = require( './html' ).singletons; + +// drop or add tab levels to JsonML tree +function reIndent ( ml, shiftBy ) { + // a bit obsessive, but there we are... + if ( !shiftBy ) { + return ml; + } + return ml.map( function ( s ) { + if ( /^\n\t+/.test( s ) ) { + if ( shiftBy < 0 ) { + s = s.slice( 0, shiftBy ); + } + else { + for ( let i = 0; i < shiftBy; i++ ) { + s += '\t'; + } + } + } + else if ( Array.isArray( s ) ) { + return reIndent( s, shiftBy ); + } + return s; + }); +} + +function escape ( text, escapeQuotes ) { + return text.replace( /&(?!(#\d{2,}|#x[\da-fA-F]{2,}|[a-zA-Z][a-zA-Z1-4]{1,6});)/g, '&' ) + .replace( //g, '>' ) + .replace( /"/g, escapeQuotes ? '"' : '"' ) + .replace( /'/g, escapeQuotes ? ''' : "'" ); +} + +function toHTML ( jsonml ) { + jsonml = jsonml.concat(); + + // basic case + if ( typeof jsonml === 'string' ) { + return escape( jsonml ); + } + + const tag = jsonml.shift(); + let attributes = {}; + let tagAttrs = ''; + const content = []; + + if ( jsonml.length && typeof jsonml[0] === 'object' && !Array.isArray( jsonml[0] ) ) { + attributes = jsonml.shift(); + } + + while ( jsonml.length ) { + content.push( toHTML( jsonml.shift() ) ); + } + + for ( const a in attributes ) { + tagAttrs += ( attributes[a] == null ) + ? ` ${ a }` + : ` ${ a }="${ escape( String( attributes[a] ), true ) }"`; + } + + // be careful about adding whitespace here for inline elements + if ( tag === '!' ) { + return ``; + } + else if ( tag in singletons ) { + return `<${ tag }${ tagAttrs } />`; + } + else { + return `<${ tag }${ tagAttrs }>${ content.join( '' ) }`; + } +} + +module.exports = { + reIndent: reIndent, + toHTML: toHTML, + escape: escape +}; diff --git a/src/merge.js b/src/merge.js new file mode 100644 index 0000000..f736819 --- /dev/null +++ b/src/merge.js @@ -0,0 +1,9 @@ +// merge object b properties into object a +module.exports = function merge ( a, b ) { + if ( b ) { + for ( const k in b ) { + a[ k ] = b[ k ]; + } + } + return a; +}; diff --git a/src/re.js b/src/re.js new file mode 100644 index 0000000..17c55ac --- /dev/null +++ b/src/re.js @@ -0,0 +1,74 @@ +/* +** Regular Expression helper methods +** +** This provides the `re` object, which contains several helper +** methods for working with big regular expressions (soup). +** +*/ + +const _cache = {}; + +const re = module.exports = { + + pattern: { + 'punct': '[!-/:-@\\[\\\\\\]-`{-~]', + 'space': '\\s' + }, + + escape: function ( src ) { + return src.replace( /[\-\[\]\{\}\(\)\*\+\?\.,\\\^\$\|#\s]/g, '\\$&' ); + }, + + collapse: function ( src ) { + return src.replace( /(?:#.*?(?:\n|$))/g, '' ) + .replace( /\s+/g, '' ); + }, + + expandPatterns: function ( src ) { + // TODO: provide escape for patterns: \[:pattern:] ? + return src.replace( /\[:\s*(\w+)\s*:\]/g, function ( m, k ) { + const ex = re.pattern[k]; + if ( ex ) { + return re.expandPatterns( ex ); + } + else { + throw new Error( 'Pattern ' + m + ' not found in ' + src ); + } + }); + }, + + isRegExp: function ( r ) { + return Object.prototype.toString.call( r ) === '[object RegExp]'; + }, + + compile: function ( src, flags ) { + if ( re.isRegExp( src ) ) { + if ( arguments.length === 1 ) { // no flags arg provided, use the RegExp one + flags = ( src.global ? 'g' : '' ) + + ( src.ignoreCase ? 'i' : '' ) + + ( src.multiline ? 'm' : '' ); + } + src = src.source; + } + // don't do the same thing twice + const ckey = src + ( flags || '' ); + if ( ckey in _cache ) { + return _cache[ ckey ]; + } + // allow classes + let rx = re.expandPatterns( src ); + // allow verbose expressions + if ( flags && /x/.test( flags ) ) { + rx = re.collapse( rx ); + } + // allow dotall expressions + if ( flags && /s/.test( flags ) ) { + rx = rx.replace( /([^\\])\./g, '$1[^\\0]' ); + } + // TODO: test if MSIE and add replace \s with [\s\u00a0] if it is? + // clean flags and output new regexp + flags = ( flags || '' ).replace( /[^gim]/g, '' ); + return ( _cache[ ckey ] = new RegExp( rx, flags ) ); + } + +}; diff --git a/src/ribbon.js b/src/ribbon.js new file mode 100644 index 0000000..6ab1948 --- /dev/null +++ b/src/ribbon.js @@ -0,0 +1,45 @@ +module.exports = function ribbon ( feed ) { + const org = String( feed ); + let slot = null; + let pos = 0; + + return { + + save: function () { + slot = pos; + }, + + load: function () { + pos = slot; + feed = org.slice( pos ); + this.$ = feed; + }, + + advance: function ( n ) { + pos += ( typeof n === 'string' ) ? n.length : n; + feed = org.slice( pos ); + this.$ = feed; + return feed; + }, + + lookbehind: function ( nchars ) { + nchars = nchars == null ? 1 : nchars; + return org.slice( pos - nchars, pos ); + }, + + startsWith: function ( s ) { + return feed.substring( 0, s.length ) === s; + }, + + valueOf: function () { + this.$ = feed; + return feed; + }, + + toString: function () { + this.$ = feed; + return feed; + } + + }; +}; diff --git a/src/textile/attr.js b/src/textile/attr.js new file mode 100644 index 0000000..294f6aa --- /dev/null +++ b/src/textile/attr.js @@ -0,0 +1,184 @@ +const reClassid = /^\(([^\(\)\n]+)\)/; +const rePaddingL = /^(\(+)/; +const rePaddingR = /^(\)+)/; +const reAlignBlock = /^(<>|<|>|=)/; +const reAlignImg = /^(<|>|=)/; +const reVAlign = /^(~|\^|\-)/; +const reColSpan = /^\\(\d+)/; +const reRowSpan = /^\/(\d+)/; +const reStyles = /^\{([^\}]*)\}/; +const reCSS = /^\s*([^:\s]+)\s*:\s*(.+)\s*$/; +const reLang = /^\[([^\[\]\n]+)\]/; + +const pbaAlignLookup = { + '<': 'left', + '=': 'center', + '>': 'right', + '<>': 'justify' +}; + +const pbaVAlignLookup = { + '~': 'bottom', + '^': 'top', + '-': 'middle' +}; + +function copyAttr ( s, blacklist ) { + if ( !s ) { return undefined; } + const d = {}; + for ( const k in s ) { + if ( k in s && ( !blacklist || !( k in blacklist ) ) ) { + d[ k ] = s[ k ]; + } + } + return d; +} + +function testBlock ( name ) { + // "in" test would be better but what about fn#.? + return /^(?:table|t[dh]|t(?:foot|head|body)|b[qc]|div|notextile|pre|h[1-6]|fn\\d+|p|###)$/.test( name ); +} + +/* + The attr bit causes massive problems for span elements when parentheses are used. + Parentheses are a total mess and, unsurprisingly, cause trip-ups: + + RC: `_{display:block}(span) span (span)_` -> `(span) span (span)` + PHP: `_{display:block}(span) span (span)_` -> `(span) span (span)` + + PHP and RC seem to mostly solve this by not parsing a final attr parens on spans if the + following character is a non-space. I've duplicated that: Class/ID is not matched on spans + if it is followed by `endToken` or . + + Lang is not matched here if it is followed by the end token. Theoretically I could limit the lang + attribute to /^\[[a-z]{2+}(\-[a-zA-Z0-9]+)*\]/ because Textile is layered on top of HTML which + only accepts valid BCP 47 language tags, but who knows what atrocities are being preformed + out there in the real world. So this attempts to emulate the other libraries. +*/ +function parseAttr ( input, element, endToken ) { + input = String( input ); + if ( !input || element === 'notextile' ) { + return undefined; + } + + let m; + const st = {}; + const o = { 'style': st }; + let remaining = input; + + const isBlock = testBlock( element ); + const isImg = element === 'img'; + const isList = element === 'li'; + const isPhrase = !isBlock && !isImg && element !== 'a'; + const reAlign = ( isImg ) ? reAlignImg : reAlignBlock; + + do { + if ( ( m = reStyles.exec( remaining ) ) ) { + m[1].split( ';' ).forEach( function ( p ) { + const d = p.match( reCSS ); + if ( d ) { st[ d[1] ] = d[2]; } + }); + remaining = remaining.slice( m[0].length ); + continue; + } + + if ( ( m = reLang.exec( remaining ) ) ) { + const rm = remaining.slice( m[0].length ); + if ( ( !rm && isPhrase ) || + ( endToken && endToken === rm.slice( 0, endToken.length ) ) ) { + m = null; + } + else { + o['lang'] = m[1]; + remaining = remaining.slice( m[0].length ); + } + continue; + } + + if ( ( m = reClassid.exec( remaining ) ) ) { + const rm = remaining.slice( m[0].length ); + if ( + ( !rm && isPhrase ) || + ( endToken && ( rm[0] === ' ' || endToken === rm.slice( 0, endToken.length ) ) ) + ) { + m = null; + } + else { + const bits = m[1].split( '#' ); + if ( bits[0] ) { o.class = bits[0]; } + if ( bits[1] ) { o.id = bits[1]; } + remaining = rm; + } + continue; + } + + if ( isBlock || isList ) { + if ( ( m = rePaddingL.exec( remaining ) ) ) { + st[ 'padding-left' ] = `${ m[1].length }em`; + remaining = remaining.slice( m[0].length ); + continue; + } + if ( ( m = rePaddingR.exec( remaining ) ) ) { + st[ 'padding-right' ] = `${ m[1].length }em`; + remaining = remaining.slice( m[0].length ); + continue; + } + } + + // only for blocks: + if ( isImg || isBlock || isList ) { + if ( ( m = reAlign.exec( remaining ) ) ) { + const align = pbaAlignLookup[ m[1] ]; + if ( isImg ) { + o[ 'align' ] = align; + } + else { + st[ 'text-align' ] = align; + } + remaining = remaining.slice( m[0].length ); + continue; + } + } + + // only for table cells + if ( element === 'td' || element === 'tr' ) { + if ( ( m = reVAlign.exec( remaining ) ) ) { + st[ 'vertical-align' ] = pbaVAlignLookup[ m[1] ]; + remaining = remaining.slice( m[0].length ); + continue; + } + } + if ( element === 'td' ) { + if ( ( m = reColSpan.exec( remaining ) ) ) { + o[ 'colspan' ] = m[1]; + remaining = remaining.slice( m[0].length ); + continue; + } + if ( ( m = reRowSpan.exec( remaining ) ) ) { + o[ 'rowspan' ] = m[1]; + remaining = remaining.slice( m[0].length ); + continue; + } + } + } + while ( m ); + + // collapse styles + const s = []; + for ( const v in st ) { + s.push( `${ v }:${ st[v] }` ); + } + if ( s.length ) { + o.style = s.join( ';' ); + } + else { + delete o.style; + } + + return ( remaining === input ) ? undefined : [ input.length - remaining.length, o ]; +} + +module.exports = { + copyAttr: copyAttr, + parseAttr: parseAttr +}; diff --git a/src/textile/deflist.js b/src/textile/deflist.js new file mode 100644 index 0000000..dd18d5e --- /dev/null +++ b/src/textile/deflist.js @@ -0,0 +1,49 @@ +/* definitions list parser */ + +const ribbon = require( '../ribbon' ); + +const reDeflist = /^((?:- (?:[^\n]\n?)+?)+:=(?: *\n[^\0]+?=:(?:\n|$)|(?:[^\0]+?(?:$|\n(?=\n|- )))))+/; +const reItem = /^((?:- (?:[^\n]\n?)+?)+):=( *\n[^\0]+?=:\s*(?:\n|$)|(?:[^\0]+?(?:$|\n(?=\n|- ))))/; + +function testDefList ( src ) { + return reDeflist.exec( src ); +} + +function parseDefList ( src, options ) { + src = ribbon( src.trim() ); + + // late loading to get around the lack of non-circular-dependency support in RequireJS + const parsePhrase = require( './phrase' ).parsePhrase; + const parseFlow = require( './flow' ).parseFlow; + + const deflist = [ 'dl', '\n' ]; + let terms; + let def; + let m; + + while ( ( m = reItem.exec( src ) ) ) { + // add terms + terms = m[1].split( /(?:^|\n)\- / ).slice( 1 ); + while ( terms.length ) { + deflist.push( '\t' + , [ 'dt' ].concat( parsePhrase( terms.shift().trim(), options ) ) + , '\n' + ); + } + // add definitions + def = m[2].trim(); + deflist.push( '\t' + , [ 'dd' ].concat( + ( /=:$/.test( def ) ) + ? parseFlow( def.slice( 0, -2 ).trim(), options ) + : parsePhrase( def, options ) + ) + , '\n' + ); + src.advance( m[0] ); + } + return deflist; +} + +exports.testDefList = testDefList; +exports.parseDefList = parseDefList; diff --git a/src/textile/flow.js b/src/textile/flow.js new file mode 100644 index 0000000..8d1dcfc --- /dev/null +++ b/src/textile/flow.js @@ -0,0 +1,267 @@ +/* +** textile flow content parser +*/ +const builder = require( '../builder' ); +const ribbon = require( '../ribbon' ); +const re = require( '../re' ); +const fixLinks = require( '../fixlinks' ); + +const { parseHtml, parseHtmlAttr, singletons, testComment, testOpenTagBlock } = require( '../html' ); + +const { parsePhrase } = require( './phrase' ); +const { copyAttr, parseAttr } = require( './attr' ); +const { testList, parseList } = require( './list' ); +const { testDefList, parseDefList } = require( './deflist' ); +const { testTable, parseTable } = require( './table' ); + +const { txblocks, txlisthd, txattr } = require( './re_ext' ); +re.pattern.txblocks = txblocks; +re.pattern.txlisthd = txlisthd; +re.pattern.txattr = txattr; + +// HTML tags allowed in the document (root) level that trigger HTML parsing +const allowedBlocktags = { + 'p': 0, + 'hr': 0, + 'ul': 1, + 'ol': 0, + 'li': 0, + 'div': 1, + 'pre': 0, + 'object': 1, + 'script': 0, + 'noscript': 0, + 'blockquote': 1, + 'notextile': 1 +}; + +const reBlock = re.compile( /^([:txblocks:])/ ); +// const reBlockSE = re.compile( /^[:txblocks:]$/ ); +const reBlockNormal = re.compile( /^(.*?)($|\r?\n(?=[:txlisthd:])|\r?\n(?:\s*\n|$)+)/, 's' ); +const reBlockExtended = re.compile( /^(.*?)($|\r?\n(?=[:txlisthd:])|\r?\n+(?=[:txblocks:][:txattr:]\.))/, 's' ); +const reRuler = /^(\-\-\-+|\*\*\*+|___+)(\r?\n\s+|$)/; +const reLinkRef = re.compile( /^\[([^\]]+)\]((?:https?:\/\/|\/)\S+)(?:\s*\n|$)/ ); +const reFootnoteDef = /^fn\d+$/; + +function paragraph ( s, tag, pba, linebreak, options ) { + tag = tag || 'p'; + let out = []; + s.split( /(?:\r?\n){2,}/ ).forEach( function ( bit, i ) { + if ( tag === 'p' && /^\s/.test( bit ) ) { + // no-paragraphs + // WTF?: Why does Textile not allow linebreaks in spaced lines + bit = bit.replace( /\r?\n[\t ]/g, ' ' ).trim(); + out = out.concat( parsePhrase( bit, options ) ); + } + else { + if ( linebreak && i ) { out.push( linebreak ); } + out.push( pba ? [ tag, pba ].concat( parsePhrase( bit, options ) ) + : [ tag ].concat( parsePhrase( bit, options ) ) ); + } + }); + return out; +}; + +function parseFlow ( src, options ) { + const list = builder(); + + let linkRefs; + let m; + + src = ribbon( src.replace( /^( *\r?\n)+/, '' ) ); + + // loop + while ( src.valueOf() ) { + src.save(); + + // link_ref -- this goes first because it shouldn't trigger a linebreak + if ( ( m = reLinkRef.exec( src ) ) ) { + if ( !linkRefs ) { linkRefs = {}; } + src.advance( m[0] ); + linkRefs[m[1]] = m[2]; + continue; + } + + // add linebreak + list.linebreak(); + + // named block + if ( ( m = reBlock.exec( src ) ) ) { + src.advance( m[0] ); + const blockType = m[0]; + let pba = parseAttr( src, blockType ); + + if ( pba ) { + src.advance( pba[0] ); + pba = pba[1]; + } + if ( ( m = /^\.(\.?)(?:\s|(?=:))/.exec( src ) ) ) { + // FIXME: this whole copyAttr seems rather strange? + // slurp rest of block + const extended = !!m[1]; + const reBlockGlob = ( extended ? reBlockExtended : reBlockNormal ); + m = reBlockGlob.exec( src.advance( m[0] ) ); + src.advance( m[0] ); + // bq | bc | notextile | pre | h# | fn# | p | ### + if ( blockType === 'bq' ) { + let inner = m[1]; + if ( ( m = /^:(\S+)\s+/.exec( inner ) ) ) { + if ( !pba ) { pba = {}; } + pba.cite = m[1]; + inner = inner.slice( m[0].length ); + } + // RedCloth adds all attr to both: this is bad because it produces duplicate IDs + const par = paragraph( inner, 'p', copyAttr( pba, { 'cite': 1, 'id': 1 }), '\n', options ); + list.add( [ 'blockquote', pba, '\n' ].concat( par ).concat( [ '\n' ] ) ); + // FIXME: looks like .linebreak can work here + } + else if ( blockType === 'bc' ) { + const subPba = ( pba ) ? copyAttr( pba, { 'id': 1 }) : null; + list.add( [ 'pre', pba, ( subPba ? [ 'code', subPba, m[1] ] : [ 'code', m[1] ] ) ] ); + } + else if ( blockType === 'notextile' ) { + list.merge( parseHtml( m[1] ) ); + } + else if ( blockType === '###' ) { + // ignore the insides + } + else if ( blockType === 'pre' ) { + // I disagree with RedCloth, but agree with PHP here: + // "pre(foo#bar).. line1\n\nline2" prevents multiline preformat blocks + // ...which seems like the whole point of having an extended pre block? + list.add( [ 'pre', pba, m[1] ] ); + } + else if ( reFootnoteDef.test( blockType ) ) { // footnote + // Need to be careful: RedCloth fails "fn1(foo#m). footnote" -- it confuses the ID + const fnid = blockType.replace( /\D+/g, '' ); + if ( !pba ) { pba = {}; } + pba.class = ( pba['class'] ? pba['class'] + ' ' : '' ) + 'footnote'; + pba.id = 'fn' + fnid; + list.add( [ 'p', pba, [ 'a', { 'href': '#fnr' + fnid }, [ 'sup', fnid ] ], ' ' ] + .concat( parsePhrase( m[1], options ) ) ); + } + else { // heading | paragraph + list.merge( paragraph( m[1], blockType, pba, '\n', options ) ); + } + continue; + } + else { + src.load(); + } + } + + // HTML comment + if ( ( m = testComment( src ) ) ) { + src.advance( m[0] + ( /(?:\s*\n+)+/.exec( src ) || [] )[0] ); + list.add( [ '!', m[1] ] ); + continue; + } + + // block HTML + if ( ( m = testOpenTagBlock( src ) ) ) { + const tag = m[1]; + const single = m[3] || tag in singletons; + const tail = m[4]; + + // Unsurprisingly, all Textile implementations I have tested have trouble parsing simple HTML: + // + // "
    a\n
    b\n
    c\n
    d" + // + // I simply match them here as there is no way anyone is using nested HTML today, or if they + // are, then this will at least output less broken HTML as redundant tags will get quoted. + + // Is block tag? ... + if ( tag in allowedBlocktags ) { + src.advance( m[0] ); + + let element = [ tag ]; + + if ( m[2] ) { + element.push( parseHtmlAttr( m[2] ) ); + } + + // single tag + if ( single ) { + // let us add the element and continue our quest... + list.add( element ); + continue; + } + // block + else { + // gulp up the rest of this block... + const reEndTag = re.compile( `^(.*?)(\\s*)()(\\s*)`, 's' ); + if ( ( m = reEndTag.exec( src ) ) ) { + src.advance( m[0] ); + if ( tag === 'pre' ) { + element.push( tail ); + element = element.concat( parseHtml( m[1].replace( /(\r?\n)+$/, '' ), { 'code': 1 }) ); + if ( m[2] ) { element.push( m[2] ); } + list.add( element ); + } + else if ( tag === 'notextile' ) { + element = parseHtml( m[1].trim() ); + list.merge( element ); + } + else if ( tag === 'script' || tag === 'noscript' ) { + element.push( tail + m[1] ); + list.add( element ); + } + else { + // These strange (and unnecessary) linebreak tests are here to get the + // tests working perfectly. In reality, this doesn't matter one bit. + if ( /\n/.test( tail ) ) { element.push( '\n' ); } + if ( /\n/.test( m[1] ) ) { + element = element.concat( parseFlow( m[1], options ) ); + } + else { + element = element.concat( parsePhrase( m[1].replace( /^ +/, '' ), options ) ); + } + if ( /\n/.test( m[2] ) ) { element.push( '\n' ); } + + list.add( element ); + } + continue; + } + } + } + src.load(); + } + + // ruler + if ( ( m = reRuler.exec( src ) ) ) { + src.advance( m[0] ); + list.add( [ 'hr' ] ); + continue; + } + + // list + if ( ( m = testList( src ) ) ) { + src.advance( m[0] ); + list.add( parseList( m[0], options ) ); + continue; + } + + // definition list + if ( ( m = testDefList( src ) ) ) { + src.advance( m[0] ); + list.add( parseDefList( m[0], options ) ); + continue; + } + + // table + if ( ( m = testTable( src ) ) ) { + src.advance( m[0] ); + list.add( parseTable( m[1], options ) ); + continue; + } + + // paragraph + m = reBlockNormal.exec( src ); + list.merge( paragraph( m[1], 'p', undefined, '\n', options ) ); + src.advance( m[0] ); + } + + return linkRefs ? fixLinks( list.get(), linkRefs ) : list.get(); +} + +exports.parseFlow = parseFlow; diff --git a/src/textile/glyph.js b/src/textile/glyph.js new file mode 100644 index 0000000..4341683 --- /dev/null +++ b/src/textile/glyph.js @@ -0,0 +1,50 @@ +/* textile glyph parser */ + +const re = require( '../re' ); + +const reApostrophe = /(\w)'(\w)/g; +const reArrow = /([^\-]|^)->/; +const reClosingDQuote = re.compile( /([^\s\[\(])"(?=$|\s|[:punct:])/g ); +const reClosingSQuote = re.compile( /([^\s\[\(])'(?=$|\s|[:punct:])/g ); +const reCopyright = /(\b ?|\s|^)(?:\(C\)|\[C\])/gi; +const reDimsign = /([\d\.,]+['"]? ?)x( ?)(?=[\d\.,]['"]?)/g; +const reDoublePrime = re.compile( /(\d*[\.,]?\d+)"(?=\s|$|[:punct:])/g ); +const reEllipsis = /([^.]?)\.{3}/g; +const reEmdash = /(^|[\s\w])--([\s\w]|$)/g; +const reEndash = / - /g; +const reOpenDQuote = /"/g; +const reOpenSQuote = /'/g; +const reRegistered = /(\b ?|\s|^)(?:\(R\)|\[R\])/gi; +const reSinglePrime = re.compile( /(\d*[\.,]?\d+)'(?=\s|$|[:punct:])/g ); +const reTrademark = /(\b ?|\s|^)(?:\((?:TM|tm)\)|\[(?:TM|tm)\])/g; + +exports.parseGlyph = function parseGlyph ( src ) { + if ( typeof src !== 'string' ) { + return src; + } + // NB: order is important here ... + return src + .replace( reArrow, '$1→' ) + .replace( reDimsign, '$1×$2' ) + .replace( reEllipsis, '$1…' ) + .replace( reEmdash, '$1—$2' ) + .replace( reEndash, ' – ' ) + .replace( reTrademark, '$1™' ) + .replace( reRegistered, '$1®' ) + .replace( reCopyright, '$1©' ) + // double quotes + .replace( reDoublePrime, '$1″' ) + .replace( reClosingDQuote, '$1”' ) + .replace( reOpenDQuote, '“' ) + // single quotes + .replace( reSinglePrime, '$1′' ) + .replace( reApostrophe, '$1’$2' ) + .replace( reClosingSQuote, '$1’' ) + .replace( reOpenSQuote, '‘' ) + // fractions and degrees + .replace( /[\(\[]1\/4[\]\)]/, '¼' ) + .replace( /[\(\[]1\/2[\]\)]/, '½' ) + .replace( /[\(\[]3\/4[\]\)]/, '¾' ) + .replace( /[\(\[]o[\]\)]/, '°' ) + .replace( /[\(\[]\+\/\-[\]\)]/, '±' ); +}; diff --git a/src/textile/list.js b/src/textile/list.js new file mode 100644 index 0000000..94c0bb4 --- /dev/null +++ b/src/textile/list.js @@ -0,0 +1,144 @@ +/* textile list parser */ +const ribbon = require( '../ribbon' ); +const re = require( '../re' ); +const merge = require( '../merge' ); + +const { parseAttr } = require( './attr' ); +const { parsePhrase } = require( './phrase' ); + +const { txlisthd } = require( './re_ext' ); +re.pattern.txlisthd = txlisthd; +const reList = re.compile( /^((?:[:txlisthd:][^\0]*?(?:\r?\n|$))+)(\s*\n|$)/, 's' ); +const reItem = re.compile( /^([#\*]+)([^\0]+?)(\n(?=[:txlisthd:])|$)/, 's' ); + +function listPad ( n ) { + let s = '\n'; + while ( n-- ) { + s += '\t'; + } + return s; +} + +function testList ( src ) { + return reList.exec( src ); +} + +function parseList ( src, options ) { + src = ribbon( src.replace( /(^|\r?\n)[\t ]+/, '$1' ) ); + + const stack = []; + const currIndex = {}; + const lastIndex = options._lst || {}; + let itemIndex = 0; + let listAttr; + let m; + let n; + let s; + + while ( ( m = reItem.exec( src ) ) ) { + const item = [ 'li' ]; + const destLevel = m[1].length; + const type = ( m[1].substr( -1 ) === '#' ) ? 'ol' : 'ul'; + let newLi = null; + let lst; + let par; + let pba; + let r; + + // list starts and continuations + if ( ( n = /^(_|\d+)/.exec( m[2] ) ) ) { + itemIndex = isFinite( n[1] ) + ? parseInt( n[1], 10 ) + : lastIndex[ destLevel ] || currIndex[ destLevel ] || 1; + m[2] = m[2].slice( n[1].length ); + } + + if ( ( pba = parseAttr( m[2], 'li' ) ) ) { + m[2] = m[2].slice( pba[0] ); + pba = pba[1]; + } + + // list control + if ( /^\.\s*$/.test( m[2] ) ) { + listAttr = pba || {}; + src.advance( m[0] ); + continue; + } + + // create nesting until we have correct level + while ( stack.length < destLevel ) { + // list always has an attribute object, this simplifies first-pba resolution + lst = [ type, {}, listPad( stack.length + 1 ), ( newLi = [ 'li' ] ) ]; + par = stack[ stack.length - 1 ]; + if ( par ) { + par.li.push( listPad( stack.length ) ); + par.li.push( lst ); + } + stack.push({ + ul: lst, + li: newLi, + // count attributes's found per list + att: 0 + }); + currIndex[ stack.length ] = 1; + } + + // remove nesting until we have correct level + while ( stack.length > destLevel ) { + r = stack.pop(); + r.ul.push( listPad( stack.length ) ); + // lists have a predictable structure - move pba from listitem to list + if ( r.att === 1 && !r.ul[3][1].substr ) { + merge( r.ul[1], r.ul[3].splice( 1, 1 )[ 0 ] ); + } + } + + // parent list + par = stack[ stack.length - 1 ]; + + if ( itemIndex ) { + par.ul[1].start = itemIndex; + currIndex[destLevel] = itemIndex; + // falsy prevents this from fireing until it is set again + itemIndex = 0; + } + if ( listAttr ) { + // "more than 1" prevent attribute transfers on list close + par.att = 9; + merge( par.ul[1], listAttr ); + listAttr = null; + } + + if ( !newLi ) { + par.ul.push( listPad( stack.length ), item ); + par.li = item; + } + if ( pba ) { + par.li.push( pba ); + par.att++; + } + Array.prototype.push.apply( par.li, parsePhrase( m[2].trim(), options ) ); + + src.advance( m[0] ); + currIndex[destLevel] = ( currIndex[destLevel] || 0 ) + 1; + } + + // remember indexes for continuations next time + options._lst = currIndex; + + while ( stack.length ) { + s = stack.pop(); + s.ul.push( listPad( stack.length ) ); + // lists have a predictable structure - move pba from listitem to list + if ( s.att === 1 && !s.ul[3][1].substr ) { + merge( s.ul[1], s.ul[3].splice( 1, 1 )[0] ); + } + } + + return s.ul; +} + +module.exports = { + testList: testList, + parseList: parseList +}; diff --git a/src/textile/phrase.js b/src/textile/phrase.js new file mode 100644 index 0000000..e881541 --- /dev/null +++ b/src/textile/phrase.js @@ -0,0 +1,238 @@ +/* textile inline parser */ + +const ribbon = require( '../ribbon' ); +const builder = require( '../builder' ); +const re = require( '../re' ); + +const { parseAttr } = require( './attr' ); +const { parseGlyph } = require( './glyph' ); +const { parseHtmlAttr, singletons, testComment, testOpenTag } = require( '../html' ); + +const { ucaps, txattr, txcite } = require( './re_ext' ); +re.pattern.txattr = txattr; +re.pattern.txcite = txcite; +re.pattern.ucaps = ucaps; + +const phraseConvert = { + '*': 'strong', + '**': 'b', + '??': 'cite', + '_': 'em', + '__': 'i', + '-': 'del', + '%': 'span', + '+': 'ins', + '~': 'sub', + '^': 'sup', + '@': 'code' +}; + +const rePhrase = /^([\[\{]?)(__?|\*\*?|\?\?|[\-\+\^~@%])/; +const reImage = re.compile( /^!(?!\s)([:txattr:](?:\.[^\n\S]|\.(?:[^\.\/]))?)([^!\s]+?) ?(?:\(((?:[^\(\)]+|\([^\(\)]+\))+)\))?!(?::([^\s]+?(?=[!-\.:-@\[\\\]-`{-~](?:$|\s)|\s|$)))?/ ); +const reImageFenced = re.compile( /^\[!(?!\s)([:txattr:](?:\.[^\n\S]|\.(?:[^\.\/]))?)([^!\s]+?) ?(?:\(((?:[^\(\)]+|\([^\(\)]+\))+)\))?!(?::([^\s]+?(?=[!-\.:-@\[\\\]-`{-~](?:$|\s)|\s|$)))?\]/ ); +// NB: there is an exception in here to prevent matching "TM)" +const reCaps = re.compile( /^((?!TM\)|tm\))[[:ucaps:]](?:[[:ucaps:]\d]{1,}(?=\()|[[:ucaps:]\d]{2,}))(?:\((.*?)\))?(?=\W|$)/ ); +const reLink = re.compile( /^"(?!\s)((?:[^\n"]|"(?![\s:])[^\n"]+"(?!:))+)"[:txcite:]/ ); +const reLinkFenced = /^\["([^\n]+?)":((?:\[[a-z0-9]*\]|[^\]])+)\]/; +const reLinkTitle = /\s*\(((?:\([^\(\)]*\)|[^\(\)])+)\)$/; +const reFootnote = /^\[(\d+)(!?)\]/; + +function parsePhrase ( src, options ) { + src = ribbon( src ); + + const list = builder(); + let m; + let pba; + + // loop + do { + src.save(); + + // linebreak -- having this first keeps it from messing to much with other phrases + if ( src.startsWith( '\r\n' ) ) { + src.advance( 1 ); // skip cartridge returns + } + if ( src.startsWith( '\n' ) ) { + src.advance( 1 ); + if ( options.breaks ) { + list.add( [ 'br' ] ); + } + list.add( '\n' ); + continue; + } + + // inline notextile + if ( ( m = /^==(.*?)==/.exec( src ) ) ) { + src.advance( m[0] ); + list.add( m[1] ); + continue; + } + + // lookbehind => /([\s>.,"'?!;:])$/ + const behind = src.lookbehind( 1 ); + const boundary = !behind || /^[\s>.,"'?!;:()]$/.test( behind ); + // FIXME: need to test right boundary for phrases as well + if ( ( m = rePhrase.exec( src ) ) && ( boundary || m[1] ) ) { + src.advance( m[0] ); + const tok = m[2]; + const fence = m[1]; + const phraseType = phraseConvert[tok]; + const code = phraseType === 'code'; + + if ( ( pba = !code && parseAttr( src, phraseType, tok ) ) ) { + src.advance( pba[0] ); + pba = pba[1]; + } + // FIXME: if we can't match the fence on the end, we should output fence-prefix as normal text + // seek end + let mMid; + let mEnd; + if ( fence === '[' ) { + mMid = '^(.*?)'; + mEnd = '(?:])'; + } + else if ( fence === '{' ) { + mMid = '^(.*?)'; + mEnd = '(?:})'; + } + else { + const t1 = re.escape( tok.charAt( 0 ) ); + mMid = ( code ) ? '^(\\S+|\\S+.*?\\S)' + : `^([^\\s${ t1 }]+|[^\\s${ t1 }].*?\\S(${ t1 }*))`; + mEnd = '(?=$|[\\s.,"\'!?;:()«»„“”‚‘’])'; + } + const rx = re.compile( `${ mMid }(${ re.escape( tok ) })${ mEnd }` ); + if ( ( m = rx.exec( src ) ) && m[1] ) { + src.advance( m[0] ); + if ( code ) { + list.add( [ phraseType, m[1] ] ); + } + else { + list.add( [ phraseType, pba ].concat( parsePhrase( m[1], options ) ) ); + } + continue; + } + // else + src.load(); + } + + // image + if ( ( m = reImage.exec( src ) ) || ( m = reImageFenced.exec( src ) ) ) { + src.advance( m[0] ); + + pba = m[1] && parseAttr( m[1], 'img' ); + const attr = pba ? pba[1] : { 'src': '' }; + let img = [ 'img', attr ]; + attr.src = m[2]; + attr.alt = m[3] ? ( attr.title = m[3] ) : ''; + + if ( m[4] ) { // +cite causes image to be wraped with a link (or link_ref)? + // TODO: support link_ref for image cite + img = [ 'a', { 'href': m[4] }, img ]; + } + list.add( img ); + continue; + } + + // html comment + if ( ( m = testComment( src ) ) ) { + src.advance( m[0] ); + list.add( [ '!', m[1] ] ); + continue; + } + // html tag + // TODO: this seems to have a lot of overlap with block tags... DRY? + if ( ( m = testOpenTag( src ) ) ) { + src.advance( m[0] ); + const tag = m[1]; + const single = m[3] || m[1] in singletons; + let element = [ tag ]; + const tail = m[4]; + if ( m[2] ) { + element.push( parseHtmlAttr( m[2] ) ); + } + if ( single ) { // single tag + list.add( element ).add( tail ); + continue; + } + else { // need terminator + // gulp up the rest of this block... + const reEndTag = re.compile( `^(.*?)()`, 's' ); + if ( ( m = reEndTag.exec( src ) ) ) { + src.advance( m[0] ); + if ( tag === 'code' ) { + element.push( tail, m[1] ); + } + else if ( tag === 'notextile' ) { + list.merge( parsePhrase( m[1], options ) ); + continue; + } + else { + element = element.concat( parsePhrase( m[1], options ) ); + } + list.add( element ); + continue; + } + // end tag is missing, treat tag as normal text... + } + src.load(); + } + + // footnote + if ( ( m = reFootnote.exec( src ) ) && /\S/.test( behind ) ) { + src.advance( m[0] ); + list.add( [ 'sup', { 'class': 'footnote', 'id': 'fnr' + m[1] }, + ( m[2] === '!' ? m[1] // "!" suppresses the link + : [ 'a', { href: '#fn' + m[1] }, m[1] ] ) + ] ); + continue; + } + + // caps / abbr + if ( ( m = reCaps.exec( src ) ) ) { + src.advance( m[0] ); + let caps = [ 'span', { 'class': 'caps' }, m[1] ]; + if ( m[2] ) { + // FIXME: use , not acronym! + caps = [ 'acronym', { 'title': m[2] }, caps ]; + } + list.add( caps ); + continue; + } + + // links + if ( ( boundary && ( m = reLink.exec( src ) ) ) || + ( m = reLinkFenced.exec( src ) ) ) { + src.advance( m[0] ); + let title = m[1].match( reLinkTitle ); + let inner = ( title ) ? m[1].slice( 0, m[1].length - title[0].length ) : m[1]; + if ( ( pba = parseAttr( inner, 'a' ) ) ) { + inner = inner.slice( pba[0] ); + pba = pba[1]; + } + else { + pba = {}; + } + if ( title && !inner ) { + inner = title[0]; + title = ''; + } + pba.href = m[2]; + if ( title ) { pba.title = title[1]; } + list.add( [ 'a', pba ].concat( parsePhrase( inner.replace( /^(\.?\s*)/, '' ), options ) ) ); + continue; + } + + // no match, move by all "uninteresting" chars + m = /([a-zA-Z0-9,.':]+|[ \f\r\t\v\xA0\u2028\u2029]+|[^\0])/.exec( src ); + if ( m ) { + list.add( m[0] ); + } + src.advance( m ? m[0].length || 1 : 1 ); + } + while ( src.valueOf() ); + + return list.get().map( parseGlyph ); +} + +exports.parsePhrase = parsePhrase; diff --git a/src/textile/re_ext.js b/src/textile/re_ext.js new file mode 100644 index 0000000..898a606 --- /dev/null +++ b/src/textile/re_ext.js @@ -0,0 +1,34 @@ +/* eslint camelcase: 0 */ + +exports.txblocks = '(?:b[qc]|div|notextile|pre|h[1-6]|fn\\d+|p|###)'; + +exports.ucaps = 'A-Z' + + // Latin extended À-Þ + '\u00c0-\u00d6\u00d8-\u00de' + + // Latin caps with embelishments and ligatures... + '\u0100\u0102\u0104\u0106\u0108\u010a\u010c\u010e\u0110\u0112\u0114\u0116\u0118\u011a\u011c\u011e\u0120\u0122\u0124\u0126\u0128\u012a\u012c\u012e\u0130\u0132\u0134\u0136\u0139\u013b\u013d\u013f' + + '\u0141\u0143\u0145\u0147\u014a\u014c\u014e\u0150\u0152\u0154\u0156\u0158\u015a\u015c\u015e\u0160\u0162\u0164\u0166\u0168\u016a\u016c\u016e\u0170\u0172\u0174\u0176\u0178\u0179\u017b\u017d' + + '\u0181\u0182\u0184\u0186\u0187\u0189-\u018b\u018e-\u0191\u0193\u0194\u0196-\u0198\u019c\u019d\u019f\u01a0\u01a2\u01a4\u01a6\u01a7\u01a9\u01ac\u01ae\u01af\u01b1-\u01b3\u01b5\u01b7\u01b8\u01bc' + + '\u01c4\u01c7\u01ca\u01cd\u01cf\u01d1\u01d3\u01d5\u01d7\u01d9\u01db\u01de\u01e0\u01e2\u01e4\u01e6\u01e8\u01ea\u01ec\u01ee\u01f1\u01f4\u01f6-\u01f8\u01fa\u01fc\u01fe' + + '\u0200\u0202\u0204\u0206\u0208\u020a\u020c\u020e\u0210\u0212\u0214\u0216\u0218\u021a\u021c\u021e\u0220\u0222\u0224\u0226\u0228\u022a\u022c\u022e\u0230\u0232\u023a\u023b\u023d\u023e' + + '\u0241\u0243-\u0246\u0248\u024a\u024c\u024e' + + '\u1e00\u1e02\u1e04\u1e06\u1e08\u1e0a\u1e0c\u1e0e\u1e10\u1e12\u1e14\u1e16\u1e18\u1e1a\u1e1c\u1e1e\u1e20\u1e22\u1e24\u1e26\u1e28\u1e2a\u1e2c\u1e2e\u1e30\u1e32\u1e34\u1e36\u1e38\u1e3a\u1e3c\u1e3e\u1e40' + + '\u1e42\u1e44\u1e46\u1e48\u1e4a\u1e4c\u1e4e\u1e50\u1e52\u1e54\u1e56\u1e58\u1e5a\u1e5c\u1e5e\u1e60\u1e62\u1e64\u1e66\u1e68\u1e6a\u1e6c\u1e6e\u1e70\u1e72\u1e74\u1e76\u1e78\u1e7a\u1e7c\u1e7e' + + '\u1e80\u1e82\u1e84\u1e86\u1e88\u1e8a\u1e8c\u1e8e\u1e90\u1e92\u1e94\u1e9e\u1ea0\u1ea2\u1ea4\u1ea6\u1ea8\u1eaa\u1eac\u1eae\u1eb0\u1eb2\u1eb4\u1eb6\u1eb8\u1eba\u1ebc\u1ebe' + + '\u1ec0\u1ec2\u1ec4\u1ec6\u1ec8\u1eca\u1ecc\u1ece\u1ed0\u1ed2\u1ed4\u1ed6\u1ed8\u1eda\u1edc\u1ede\u1ee0\u1ee2\u1ee4\u1ee6\u1ee8\u1eea\u1eec\u1eee\u1ef0\u1ef2\u1ef4\u1ef6\u1ef8\u1efa\u1efc\u1efe' + + '\u2c60\u2c62-\u2c64\u2c67\u2c69\u2c6b\u2c6d-\u2c70\u2c72\u2c75\u2c7e\u2c7f' + + '\ua722\ua724\ua726\ua728\ua72a\ua72c\ua72e\ua732\ua734\ua736\ua738\ua73a\ua73c\ua73e' + + '\ua740\ua742\ua744\ua746\ua748\ua74a\ua74c\ua74e\ua750\ua752\ua754\ua756\ua758\ua75a\ua75c\ua75e\ua760\ua762\ua764\ua766\ua768\ua76a\ua76c\ua76e\ua779\ua77b\ua77d\ua77e' + + '\ua780\ua782\ua784\ua786\ua78b\ua78d\ua790\ua792\ua7a0\ua7a2\ua7a4\ua7a6\ua7a8\ua7aa'; + +exports.txcite = ':((?:[^\\s()]|\\([^\\s()]+\\)|[()])+?)(?=[!-\\.:-@\\[\\\\\\]-`{-~]+(?:$|\\s)|$|\\s)'; + +const attr_class = exports.attr_class = '\\([^\\)]+\\)'; +const attr_style = exports.attr_style = '\\{[^\\}]+\\}'; +const attr_lang = exports.attr_lang = '\\[[^\\[\\]]+\\]'; +const attr_align = exports.attr_align = '(?:<>|<|>|=)'; +const attr_pad = exports.attr_pad = '[\\(\\)]+'; + +const txattr = exports.txattr = `(?:${ attr_class }|${ attr_style }|${ attr_lang }|${ attr_align }|${ attr_pad })*`; + +exports.txlisthd = `[\\t ]*[\\#\\*]*(\\*|\\#(?:_|\\d+)?)${ txattr }(?: \\S|\\.\\s*(?=\\S|\\n))`; diff --git a/src/textile/table.js b/src/textile/table.js new file mode 100644 index 0000000..9d4e03b --- /dev/null +++ b/src/textile/table.js @@ -0,0 +1,206 @@ +/* textile table parser */ + +const re = require( '../re' ); +const merge = require( '../merge' ); +const ribbon = require( '../ribbon' ); + +const { parseAttr } = require( './attr' ); +const { parsePhrase } = require( './phrase' ); +const { reIndent } = require( '../jsonml' ); + +const { txattr } = require( './re_ext' ); +re.pattern.txattr = txattr; + +const reTable = re.compile( /^((?:table[:txattr:]\.(?:\s(.+?))\s*\n)?(?:(?:[:txattr:]\.[^\n\S]*)?\|.*?\|[^\n\S]*(?:\n|$))+)([^\n\S]*\n)?/, 's' ); +const reHead = /^table(_?)([^\n]*?)\.(?:[ \t](.+?))?\s*\n/; +const reRow = re.compile( /^(?:\|([~\^\-][:txattr:])\.\s*\n)?([:txattr:]\.[^\n\S]*)?\|(.*?)\|[^\n\S]*(\n|$)/, 's' ); +const reCaption = /^\|=([^\n+]*)\n/; +const reColgroup = /^\|:([^\n+]*)\|[\r\t ]*\n/; +const reRowgroup = /^\|([\^\-~])([^\n+]*)\.[ \t\r]*\n/; + +const charToTag = { + '^': 'thead', + '~': 'tfoot', + '-': 'tbody' +}; + +function parseColgroup ( src ) { + const colgroup = [ 'colgroup', {} ]; + src.split( '|' ) + .forEach( function ( s, isCol ) { + const col = ( isCol ) ? {} : colgroup[ 1 ]; + let d = s.trim(); + let m; + if ( d ) { + if ( ( m = /^\\(\d+)/.exec( d ) ) ) { + col.span = +m[ 1 ]; + d = d.slice( m[ 0 ].length ); + } + if ( ( m = parseAttr( d, 'col' ) ) ) { + merge( col, m[ 1 ] ); + d = d.slice( m[ 0 ] ); + } + if ( ( m = /\b\d+\b/.exec( d ) ) ) { + col.width = +m[0]; + } + } + if ( isCol ) { + colgroup.push( '\n\t\t', [ 'col', col ] ); + } + }); + return colgroup.concat( [ '\n\t' ] ); +} + +function testTable ( src ) { + return reTable.exec( src ); +} + +function parseTable ( src, options ) { + src = ribbon( src.trim() ); + + const rowgroups = []; + let colgroup; + let caption; + const tAttr = {}; + let tCurr; + let row; + let inner; + let pba; + let more; + let m; + let extended = 0; + + const setRowGroup = function ( type, pba ) { + tCurr = [ type, pba || {} ]; + rowgroups.push( tCurr ); + }; + + if ( ( m = reHead.exec( src ) ) ) { + // parse and apply table attr + src.advance( m[0] ); + pba = parseAttr( m[2], 'table' ); + if ( pba ) { + merge( tAttr, pba[1] ); + } + if ( m[3] ) { + tAttr.summary = m[3]; + } + } + + // caption + if ( ( m = reCaption.exec( src ) ) ) { + caption = [ 'caption' ]; + if ( ( pba = parseAttr( m[1], 'caption' ) ) ) { + caption.push( pba[1] ); + m[1] = m[1].slice( pba[0] ); + } + if ( /\./.test( m[1] ) ) { // mandatory "." + caption.push( m[1].slice( 1 ).replace( /\|\s*$/, '' ).trim() ); + extended++; + src.advance( m[0] ); + } + else { + caption = null; + } + } + + do { + // colgroup + if ( ( m = reColgroup.exec( src ) ) ) { + colgroup = parseColgroup( m[1] ); + extended++; + } + // "rowgroup" (tbody, thead, tfoot) + else if ( ( m = reRowgroup.exec( src ) ) ) { + // PHP allows any amount of these in any order + // and simply translates them straight through + // the same is done here. + const tag = charToTag[ m[1] ] || 'tbody'; + pba = parseAttr( `${ m[2] } `, tag ); + setRowGroup( tag, pba && pba[1] ); + extended++; + } + // row + else if ( ( m = reRow.exec( src ) ) ) { + if ( !tCurr ) { setRowGroup( 'tbody' ); } + + row = [ 'tr' ]; + + if ( m[2] && ( pba = parseAttr( m[2], 'tr' ) ) ) { + // FIXME: requires "\.\s?" -- else what ? + row.push( pba[1] ); + } + + tCurr.push( '\n\t\t', row ); + inner = ribbon( m[3] ); + + do { + inner.save(); + + // cell loop + const th = inner.startsWith( '_' ); + let cell = [ th ? 'th' : 'td' ]; + if ( th ) { + inner.advance( 1 ); + } + + pba = parseAttr( inner, 'td' ); + if ( pba ) { + inner.advance( pba[0] ); + cell.push( pba[1] ); // FIXME: don't do this if next text fails + } + + if ( pba || th ) { + const p = /^\.\s*/.exec( inner ); + if ( p ) { + inner.advance( p[0] ); + } + else { + cell = [ 'td' ]; + inner.load(); + } + } + + const mx = /^(==.*?==|[^\|])*/.exec( inner ); + cell = cell.concat( parsePhrase( mx[0], options ) ); + row.push( '\n\t\t\t', cell ); + more = inner.valueOf().charAt( mx[0].length ) === '|'; + inner.advance( mx[0].length + 1 ); + } + while ( more ); + + row.push( '\n\t\t' ); + } + // + if ( m ) { + src.advance( m[0] ); + } + } + while ( m ); + + // assemble table + let table = [ 'table', tAttr ]; + if ( extended ) { + if ( caption ) { + table.push( '\n\t', caption ); + } + if ( colgroup ) { + table.push( '\n\t', colgroup ); + } + rowgroups.forEach( function ( tbody ) { + table.push( '\n\t', tbody.concat( [ '\n\t' ] ) ); + }); + } + else { + table = table.concat( reIndent( rowgroups[0].slice( 2 ), -1 ) ); + } + + table.push( '\n' ); + return table; +} + +module.exports = { + parseColgroup: parseColgroup, + parseTable: parseTable, + testTable: testTable +}; diff --git a/test/basic.js b/test/basic.js new file mode 100644 index 0000000..6ec8456 --- /dev/null +++ b/test/basic.js @@ -0,0 +1,1137 @@ +// basic.yml +import test from 'ava'; +import textile from '../src'; + +test( 'paragraphs', function ( t ) { + let tx = "A single paragraph.\n\n\ +Followed by another."; + t.is( textile.convert( tx ), + "

    A single paragraph.

    \n\ +

    Followed by another.

    ", tx ); +}); + + +test( 'blocks with spaces on the blank line in between', function ( t ) { + let tx = "This is line one\n\ + \n\ +This is line two"; + t.is( textile.convert( tx ), + "

    This is line one

    \n\ +

    This is line two

    ", tx ); +}); + + +test( 'blocks with tabl on the blank line in between', function ( t ) { + let tx = "This is line one\n\ +\t\n\ +This is line two"; + t.is( textile.convert( tx ), + "

    This is line one

    \n\ +

    This is line two

    ", tx ); +}); + + +test( 'block containing block start', function ( t ) { + let tx = "I saw a ship. It ate my elephant."; + t.is( textile.convert( tx ), + "

    I saw a ship. It ate my elephant.

    ", tx ); +}); + + +test( 'extended block containing block start', function ( t ) { + let tx = "p.. I saw a ship. It ate my elephant.\n\n\ +When the elephant comes to take a p. you..."; + t.is( textile.convert( tx ), + "

    I saw a ship. It ate my elephant.

    \n\ +

    When the elephant comes to take a p. you…

    ", tx ); +}); + + +test( 'blockquote containing block start', function ( t ) { + let tx = "bq. I saw a ship. It ate my elephant."; + t.is( textile.convert( tx ), + "
    \n\ +

    I saw a ship. It ate my elephant.

    \n\ +
    ", tx ); +}); + + +test( 'extended blockquote containing block start', function ( t ) { + let tx = "bq.. I saw a ship. It ate my elephant.\n\n\ +When the elephant comes to take a p. you..."; + t.is( textile.convert( tx ), + "
    \n\ +

    I saw a ship. It ate my elephant.

    \n\ +

    When the elephant comes to take a p. you…

    \n\ +
    ", tx ); +}); + + +test( 'notextile block', function ( t ) { + let tx = "Some text:\n\n\ +\n\ +
    \n\
    +Some code\n\
    +
    \n\ +
    \n\n\ +Some more text."; + t.is( textile.convert( tx ), + "

    Some text:

    \n\ +
    \n\
    +Some code\n\
    +
    \n\ +

    Some more text.

    ", tx ); +}); + + +test( 'notextile block containing block start', function ( t ) { + let tx = "notextile. I saw a ship. It ate my elephant."; + t.is( textile.convert( tx ), + "I saw a ship. It ate my elephant.", tx ); +}); + + +test( 'extended notextile block containing block start', function ( t ) { + let tx = "notextile.. I saw a ship. It ate my elephant.\n\n\ +When the elephant comes to take a p. you..."; + t.is( textile.convert( tx ), + "I saw a ship. It ate my elephant.\n\n\ +When the elephant comes to take a p. you...", tx ); +}); + + +test( 'pre block containing block start', function ( t ) { + let tx = "pre. I saw a ship. It ate my elephant."; + t.is( textile.convert( tx ), + "
    I saw a ship. It ate my elephant.
    ", tx ); +}); + + +test( 'extended pre block containing block start', function ( t ) { + let tx = "pre.. I saw a ship. It ate my elephant.\n\n\ +When the elephant comes to take a p. you..."; + t.is( textile.convert( tx ), + "
    I saw a ship. It ate my elephant.\n\n\
    +When the elephant comes to take a p. you...
    ", tx ); +}); + + +test( 'html tags', function ( t ) { + let tx = "I am very serious.\n\n\ +
    \n\
    +  I am very serious.\n\
    +
    "; + t.is( textile.convert( tx ), + "

    I am very serious.

    \n\ +
    \n\
    +  I am <b>very</b> serious.\n\
    +
    ", tx ); +}); + + +test( 'line breaks', function ( t ) { + let tx = "I spoke.\n\ +And none replied."; + t.is( textile.convert( tx ), + "

    I spoke.
    \n\ +And none replied.

    ", tx ); +}); + + +test( 'curly quotes', function ( t ) { + let tx = "\"Observe!\""; + t.is( textile.convert( tx ), + "

    “Observe!”

    ", tx ); +}); + + +test( 'quotes contained in multi-paragraph quotes', function ( t ) { + let tx = "\"I first learned about this thing called \"Redcloth\" several years ago.\n\n\ +\"It's wonderful.\""; + t.is( textile.convert( tx ), + "

    “I first learned about this thing called “Redcloth” several years ago.

    \n\ +

    “It’s wonderful.”

    ", tx ); +}); + + +test( 'double hyphens', function ( t ) { + let tx = "Observe--very nice!"; + t.is( textile.convert( tx ), + "

    Observe—very nice!

    ", tx ); +}); + + +test( 'double hyphens with spaces', function ( t ) { + let tx = "Observe -- very nice!"; + t.is( textile.convert( tx ), + "

    Observe — very nice!

    ", tx ); +}); + + +test( 'parenthetical phrase set off with em dashes', function ( t ) { + let tx = "An emdash indicates a parenthetical thought--like this one--which is set apart from the rest of a sentence."; + t.is( textile.convert( tx ), + "

    An emdash indicates a parenthetical thought—like this one—which is set apart from the rest of a sentence.

    ", tx ); +}); + + +test( 'parenthetical phrase set off with em dashes surrounded by spaces', function ( t ) { + let tx = "An emdash indicates a parenthetical thought -- like this one -- which is set apart from the rest of a sentence."; + t.is( textile.convert( tx ), + "

    An emdash indicates a parenthetical thought — like this one — which is set apart from the rest of a sentence.

    ", tx ); +}); + + +test( 'single hyphens with spaces', function ( t ) { + let tx = "Observe - tiny and brief."; + t.is( textile.convert( tx ), + "

    Observe – tiny and brief.

    ", tx ); +}); + + +test( 'midword hyphens ', function ( t ) { + let tx = "Observe the nicely-done hyphen."; + t.is( textile.convert( tx ), + "

    Observe the nicely-done hyphen.

    ", tx ); +}); + + +test( 'ellipses', function ( t ) { + let tx = "Observe..."; + t.is( textile.convert( tx ), + "

    Observe…

    ", tx ); +}); + + +test( 'dimension sign', function ( t ) { + let tx = "Observe: 2x3."; + t.is( textile.convert( tx ), + "

    Observe: 2×3.

    ", tx ); +}); + + +test( 'dimension sign with space after', function ( t ) { + let tx = "The room is 2x3 inches big."; + t.is( textile.convert( tx ), + "

    The room is 2×3 inches big.

    ", tx ); +}); + + +test( 'dimension sign with spaces', function ( t ) { + let tx = "Observe: 2 x 4."; + t.is( textile.convert( tx ), + "

    Observe: 2 × 4.

    ", tx ); +}); + + +test( 'dimension signs chained', function ( t ) { + let tx = "Observe: 2x3x4."; + t.is( textile.convert( tx ), + "

    Observe: 2×3×4.

    ", tx ); +}); + + +test( 'dimension signs with double primes', function ( t ) { + let tx = "My mouse: 2.5\" x 4\"."; + t.is( textile.convert( tx ), + "

    My mouse: 2.5″ × 4″.

    ", tx ); +}); + + +test( 'dimension signs with single primes', function ( t ) { + let tx = "My office: 5' x 4.5'."; + t.is( textile.convert( tx ), + "

    My office: 5′ × 4.5′.

    ", tx ); +}); + + +test( 'trademark and copyright', function ( t ) { + let tx = "one(TM), two(R), three(C)."; + t.is( textile.convert( tx ), + "

    one™, two®, three©.

    ", tx ); +}); + + +test( 'headers', function ( t ) { + let tx = "h3. Header 3"; + t.is( textile.convert( tx ), + "

    Header 3

    ", tx ); +}); + + +test( 'blockquote', function ( t ) { + let tx = "Any old text\n\n\ +bq. A block quotation.\n\n\ +Any old text"; + t.is( textile.convert( tx ), + "

    Any old text

    \n\ +
    \n\ +

    A block quotation.

    \n\ +
    \n\ +

    Any old text

    ", tx ); +}); + + +test( 'footnote reference', function ( t ) { + let tx = "This is covered elsewhere[1]."; + t.is( textile.convert( tx ), + "

    This is covered elsewhere1.

    ", tx ); +}); + + +test( 'footnote', function ( t ) { + let tx = "fn1. Down here, in fact."; + t.is( textile.convert( tx ), + "

    1 Down here, in fact.

    ", tx ); +}); + + +test( 'em', function ( t ) { + let tx = "I _believe_ every word."; + t.is( textile.convert( tx ), + "

    I believe every word.

    ", tx ); +}); + + +test( 'strong', function ( t ) { + let tx = "And then? She *fell*!"; + t.is( textile.convert( tx ), + "

    And then? She fell!

    ", tx ); +}); + + +test( 'strong phrase beginning with a number', function ( t ) { + let tx = "*10 times as many*"; + t.is( textile.convert( tx ), + "

    10 times as many

    ", tx ); +}); + + +test( 'force bold italics', function ( t ) { + let tx = "I __know__.\n\ +I **really** __know__."; + t.is( textile.convert( tx ), + "

    I know.
    \n\ +I really know.

    ", tx ); +}); + + +test( 'citation', function ( t ) { + let tx = "??Cat's Cradle?? by Vonnegut"; + t.is( textile.convert( tx ), + "

    Cat’s Cradle by Vonnegut

    ", tx ); +}); + + +test( 'code phrases', function ( t ) { + let tx = "Convert with @r.to_html@"; + t.is( textile.convert( tx ), + "

    Convert with r.to_html

    ", tx ); +}); + + +test( 'code phrases not created with multiple email addresses', function ( t ) { + let tx = "Please email why@domain.com or jason@domain.com."; + t.is( textile.convert( tx ), + "

    Please email why@domain.com or jason@domain.com.

    ", tx ); +}); + + +test( 'del', function ( t ) { + let tx = "I'm -sure- not sure."; + t.is( textile.convert( tx ), + "

    I’m sure not sure.

    ", tx ); +}); + + +test( 'del beginning a phrase', function ( t ) { + let tx = "-delete-"; + t.is( textile.convert( tx ), + "

    delete

    ", tx ); +}); + + +test( 'ins', function ( t ) { + let tx = "You are a +pleasant+ child."; + t.is( textile.convert( tx ), + "

    You are a pleasant child.

    ", tx ); +}); + + +test( 'superscript', function ( t ) { + let tx = "a ^2^ + b ^2^ = c ^2^"; + t.is( textile.convert( tx ), + "

    a 2 + b 2 = c 2

    ", tx ); +}); + + +test( 'parenthetical superscript phrase', function ( t ) { + let tx = "^(image courtesy NASA)^"; + t.is( textile.convert( tx ), + "

    (image courtesy NASA)

    ", tx ); +}); + + +test( 'subscript', function ( t ) { + let tx = "log ~2~ x"; + t.is( textile.convert( tx ), + "

    log 2 x

    ", tx ); +}); + + +test( 'parenthetical subscript phrase', function ( t ) { + let tx = "~(image courtesy NASA)~"; + t.is( textile.convert( tx ), + "

    (image courtesy NASA)

    ", tx ); +}); + + +test( 'tight superscript and subscript', function ( t ) { + let tx = "f(x, n) = log[~4~]x[^n^]"; + t.is( textile.convert( tx ), + "

    f(x, n) = log4xn

    ", tx ); +}); + + +test( 'span', function ( t ) { + let tx = "I'm %unaware% of most soft drinks."; + t.is( textile.convert( tx ), + "

    I’m unaware of most soft drinks.

    ", tx ); +}); + + +test( 'style span', function ( t ) { + let tx = "I'm %{color:red}unaware%\n\ +of most %{font-size:0.5em;}soft drinks%."; + t.is( textile.convert( tx ), + "

    I’m unaware
    \n\ +of most soft drinks.

    ", tx ); +}); + + +test( 'percent sign', function ( t ) { + let tx = "http://blah.com/one%20two%20three\n\ +(min)5%-95%(max)"; + t.is( textile.convert( tx ), + "

    http://blah.com/one%20two%20three
    \n\ +(min)5%-95%(max)

    ", tx ); +}); + + +test( 'css class', function ( t ) { + let tx = "p(example1). An example"; + t.is( textile.convert( tx ), + "

    An example

    ", tx ); +}); + + +test( 'css id', function ( t ) { + let tx = "p(#big-red). Red here"; + t.is( textile.convert( tx ), + "

    Red here

    ", tx ); +}); + + +test( 'css id with initial uppercase', function ( t ) { + let tx = "p(#Foo). bar"; + t.is( textile.convert( tx ), + "

    bar

    ", tx ); +}); + + +test( 'css class uppercase', function ( t ) { + let tx = "p(fooBar). baz"; + t.is( textile.convert( tx ), + "

    baz

    ", tx ); +}); + + +test( 'class and id combined', function ( t ) { + let tx = "p(example1#big-red2). Red here"; + t.is( textile.convert( tx ), + "

    Red here

    ", tx ); +}); + + +test( 'css style', function ( t ) { + let tx = "p{color:blue;margin:30px;font-size:120%;font-family:'Comic Sans'}. Spacey blue"; + t.is( textile.convert( tx ), + "

    Spacey blue

    ", tx ); +}); + + +test( 'language designations', function ( t ) { + let tx = "p[fr]. rouge"; + t.is( textile.convert( tx ), + "

    rouge

    ", tx ); +}); + + +test( 'block attributes on phrase modifiers', function ( t ) { + let tx = "I seriously *{color:red}blushed*\n\ +when I _(big)sprouted_ that\n\ +corn stalk from my\n\ +%[es]cabeza%."; + t.is( textile.convert( tx ), + "

    I seriously blushed
    \n\ +when I sprouted that
    \n\ +corn stalk from my
    \n\ +cabeza.

    ", tx ); +}); + + +test( 'inline attributes preceded by text are treated as literal', function ( t ) { + let tx = "I *seriously {color:red}blushed*\n\ +when I _first (big)sprouted_ that\n\ +corn stalk from my\n\ +%grande [es]cabeza%."; + t.is( textile.convert( tx ), + "

    I seriously {color:red}blushed
    \n\ +when I first (big)sprouted that
    \n\ +corn stalk from my
    \n\ +grande [es]cabeza.

    ", tx ); +}); + + +test( 'align justified', function ( t ) { + let tx = "p<>. justified"; + t.is( textile.convert( tx ), + "

    justified

    ", tx ); +}); + + +test( 'indentation', function ( t ) { + let tx = "p))). right ident 3em"; + t.is( textile.convert( tx ), + "

    right ident 3em

    ", tx ); +}); + + +test( 'indentation and alignment', function ( t ) { + let tx = "h2()>. Bingo."; + t.is( textile.convert( tx ), + "

    Bingo.

    ", tx ); +}); + + +test( 'many modifiers combined', function ( t ) { + let tx = "h3()>[no]{color:red}. Bingo"; + t.is( textile.convert( tx ), + "

    Bingo

    ", tx ); +}); + + +test( 'code blocks', function ( t ) { + let tx = "
    \n\
    +\n\
    +  a.gsub!( /\n\
    +
    "; + t.is( textile.convert( tx ), + "
    \n\
    +\n\
    +  a.gsub!( /</, '' )\n\
    +\n\
    +
    ", tx ); +}); + + +test( 'div tags', function ( t ) { + let tx = "
    \n\n\ +h3. Sidebar\n\n\ +\"Hobix\":http://hobix.com/\n\ +\"Ruby\":http://ruby-lang.org/\n\n\ +
    \n\n\ +The main text of the page goes here and will stay to the left of the sidebar."; + t.is( textile.convert( tx ), + "
    \n\ +

    Sidebar

    \n\ +

    Hobix
    \n\ +Ruby

    \n\ +
    \n\ +

    The main text of the page goes here and will stay to the left of the sidebar.

    ", tx ); +}); + + +test( 'numbered list', function ( t ) { + let tx = "# A first item\n\ +# A second item\n\ +# A third"; + t.is( textile.convert( tx ), + "
      \n\ +\t
    1. A first item
    2. \n\ +\t
    3. A second item
    4. \n\ +\t
    5. A third
    6. \n\ +
    ", tx ); +}); + + +test( 'nested numbered lists', function ( t ) { + let tx = "# Fuel could be:\n\ +## Coal\n\ +## Gasoline\n\ +## Electricity\n\ +# Humans need only:\n\ +## Water\n\ +## Protein"; + t.is( textile.convert( tx ), + "
      \n\ +\t
    1. Fuel could be:\n\ +\t
        \n\ +\t\t
      1. Coal
      2. \n\ +\t\t
      3. Gasoline
      4. \n\ +\t\t
      5. Electricity
      6. \n\ +\t
    2. \n\ +\t
    3. Humans need only:\n\ +\t
        \n\ +\t\t
      1. Water
      2. \n\ +\t\t
      3. Protein
      4. \n\ +\t
    4. \n\ +
    ", tx ); +}); + + +test( 'bulleted list', function ( t ) { + let tx = "* A first item\n\ +* A second item\n\ +* A third"; + t.is( textile.convert( tx ), + "
      \n\ +\t
    • A first item
    • \n\ +\t
    • A second item
    • \n\ +\t
    • A third
    • \n\ +
    ", tx ); +}); + + +test( 'nested bulleted lists', function ( t ) { + let tx = "* Fuel could be:\n\ +** Coal\n\ +** Gasoline\n\ +** Electricity\n\ +* Humans need only:\n\ +** Water\n\ +** Protein"; + t.is( textile.convert( tx ), + "
      \n\ +\t
    • Fuel could be:\n\ +\t
        \n\ +\t\t
      • Coal
      • \n\ +\t\t
      • Gasoline
      • \n\ +\t\t
      • Electricity
      • \n\ +\t
    • \n\ +\t
    • Humans need only:\n\ +\t
        \n\ +\t\t
      • Water
      • \n\ +\t\t
      • Protein
      • \n\ +\t
    • \n\ +
    ", tx ); +}); + + +test( 'links', function ( t ) { + let tx = "I searched \"Google\":http://google.com."; + t.is( textile.convert( tx ), + "

    I searched Google.

    ", tx ); +}); + + +test( 'link aliases', function ( t ) { + let tx = "I am crazy about \"Hobix\":hobix\n\ +and \"it's\":hobix \"all\":hobix I ever\n\ +\"link to\":hobix!\n\n\ +[hobix]http://hobix.com"; + t.is( textile.convert( tx ), + "

    I am crazy about Hobix
    \n\ +and it’s all I ever
    \n\ +link to!

    ", tx ); +}); + + +test( 'image', function ( t ) { + let tx = "!http://hobix.com/sample.jpg!"; + t.is( textile.convert( tx ), + "

    \"\"

    ", tx ); +}); + + +test( 'image title', function ( t ) { + let tx = "!openwindow1.gif(Bunny.)!"; + t.is( textile.convert( tx ), + "

    \"Bunny.\"

    ", tx ); +}); + + +test( 'image links', function ( t ) { + let tx = "!openwindow1.gif!:http://hobix.com/"; + t.is( textile.convert( tx ), + "

    \"\"

    ", tx ); +}); + + +test( 'image alignments', function ( t ) { + let tx = "!>obake.gif!\n\n\ +And others sat all round the small\n\ +machine and paid it to sing to them."; + t.is( textile.convert( tx ), + "

    \"\"

    \n\ +

    And others sat all round the small
    \n\ +machine and paid it to sing to them.

    ", tx ); +}); + + +test( 'acronym definitions', function ( t ) { + let tx = "We use CSS(Cascading Style Sheets)."; + t.is( textile.convert( tx ), + "

    We use CSS.

    ", tx ); +}); + + +test( 'two-letter acronyms', function ( t ) { + let tx = "It employs AI(artificial intelligence) processing."; + t.is( textile.convert( tx ), + "

    It employs AI processing.

    ", tx ); +}); + + +test( 'tables', function ( t ) { + let tx = "| name | age | sex |\n\ +| joan | 24 | f |\n\ +| archie | 29 | m |\n\ +| bella | 45 | f |"; + t.is( textile.convert( tx ), + "
    \n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
    name age sex
    joan 24 f
    archie 29 m
    bella 45 f
    ", tx ); +}); + + +test( 'table headers', function ( t ) { + let tx = "|_. name |_. age |_. sex |\n\ +| joan | 24 | f |\n\ +| archie | 29 | m |\n\ +| bella | 45 | f |"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
    name age sex
    joan 24 f
    archie 29 m
    bella 45 f
    ", tx ); +}); + + +test( 'table cell attributes', function ( t ) { + let tx = "|_. attribute list |\n\ +|<. align left |\n\ +|>. align right|\n\ +|=. center |\n\ +|<>. justify |\n\ +|^. valign top |\n\ +|~. bottom |"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +
    attribute list
    align left
    align right
    center
    justify
    valign top
    bottom
    ", tx ); +}); + + +test( 'table colspan', function ( t ) { + let tx = "|\\2. spans two cols |\n\ +| col 1 | col 2 |"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
    spans two cols
    col 1 col 2
    ", tx ); +}); + + +test( 'table rowspan', function ( t ) { + let tx = "|/3. spans 3 rows | a |\n\ +| b |\n\ +| c |"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +
    spans 3 rows a
    b
    c
    ", tx ); +}); + + +test( 'block attributes applied to table cells', function ( t ) { + let tx = "|{background:#ddd}. Grey cell|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\n\ +
    Grey cell
    ", tx ); +}); + + +test( 'block attributes applied to a table', function ( t ) { + let tx = "table{border:1px solid black}.\n\ +|This|is|a|row|\n\ +|This|is|a|row|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
    Thisisarow
    Thisisarow
    ", tx ); +}); + + +test( 'block attributes applied to a table row', function ( t ) { + let tx = "|This|is|a|row|\n\ +{background:#ddd}. |This|is|grey|row|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
    Thisisarow
    Thisisgreyrow
    ", tx ); +}); + + +test( 'extended block followed by pre block', function ( t ) { + let tx = "div.. Just a test.\n\n\ +Second div.\n\n\ +pre. A pre block ends it."; + t.is( textile.convert( tx ), + "

    Just a test.
    \n\ +
    Second div.
    \n\ +
    A pre block ends it.
    ", tx ); +}); + + +test( 'extended block followed by blockquote', function ( t ) { + let tx = "div.. Just a test.\n\n\ +Second div.\n\n\ +bq. A blockquote ends it."; + t.is( textile.convert( tx ), + "
    Just a test.
    \n\ +
    Second div.
    \n\ +
    \n\ +

    A blockquote ends it.

    \n\ +
    ", tx ); +}); + + +test( 'extended block followed by block code', function ( t ) { + let tx = "div.. Just a test.\n\n\ +Second div.\n\n\ +bc. A blockcode ends it."; + t.is( textile.convert( tx ), + "
    Just a test.
    \n\ +
    Second div.
    \n\ +
    A blockcode ends it.
    ", tx ); +}); + + +test( 'extended block followed by notextile block', function ( t ) { + let tx = "div.. Just a test.\n\n\ +Second div.\n\n\ +notextile. A notextile block ends it."; + t.is( textile.convert( tx ), + "
    Just a test.
    \n\ +
    Second div.
    \n\ +A notextile block ends it.", tx ); +}); + + +test( 'simple parentheses', function ( t ) { + let tx = "before (in parens) after"; + t.is( textile.convert( tx ), + "

    before (in parens) after

    ", tx ); +}); + + +test( 'parentheses in underscores', function ( t ) { + let tx = "before _(in parens)_ after"; + t.is( textile.convert( tx ), + "

    before (in parens) after

    ", tx ); +}); + + +test( 'parentheses in asterisks', function ( t ) { + let tx = "before *(in parens)* after"; + t.is( textile.convert( tx ), + "

    before (in parens) after

    ", tx ); +}); + + +test( 'parentheses in underscores in quotes', function ( t ) { + let tx = "\"before _(in parens)_ after\""; + t.is( textile.convert( tx ), + "

    “before (in parens) after”

    ", tx ); +}); + + +test( 'underscores in parentheses', function ( t ) { + let tx = "one _two three_ (four _five six_) seven"; + t.is( textile.convert( tx ), + "

    one two three (four five six) seven

    ", tx ); +}); + + +test( 'underscores in parentheses in quotes', function ( t ) { + let tx = "\"one _two three_ (four _five six_) seven\""; + t.is( textile.convert( tx ), + "

    “one two three (four five six) seven”

    ", tx ); +}); + + +test( 'underscores in parentheses 2', function ( t ) { + let tx = "one (two _three four_) five"; + t.is( textile.convert( tx ), + "

    one (two three four) five

    ", tx ); +}); + + +test( 'underscores in parentheses in quotes 2', function ( t ) { + let tx = "\"one (two _three four_) five\""; + t.is( textile.convert( tx ), + "

    “one (two three four) five”

    ", tx ); +}); + + +test( 'caps in parentheses', function ( t ) { + let tx = "IBM or (HAL)"; + t.is( textile.convert( tx ), + "

    IBM or (HAL)

    ", tx ); +}); + + +test( 'phrase modifiers in parentheses', function ( t ) { + let tx = "__Amanita__s are mushrooms.\n\ +Lungworts (__Lobaria__) are lichens.\n\ +Blah blah (normal text **bold**) blah."; + t.is( textile.convert( tx ), + "

    __Amanita__s are mushrooms.
    \n\ +Lungworts (Lobaria) are lichens.
    \n\ +Blah blah (normal text bold) blah.

    ", tx ); +}); + + +test( 'square brackets are preserved', function ( t ) { + let tx = "citation [\"(Berk.) Hilton\"], see\n\ +[Papers \"blah blah.\"]"; + t.is( textile.convert( tx ), + "

    citation [“(Berk.) Hilton”], see
    \n\ +[Papers “blah blah.”]

    ", tx ); +}); + + +test( 'horizontal rule using asterisks', function ( t ) { + let tx = "Just some *** text\n\n\ +***\n\n\ +Some more text."; + t.is( textile.convert( tx ), + "

    Just some *** text

    \n\ +
    \n\ +

    Some more text.

    ", tx ); +}); + + +test( 'horizontal rule using more than three asterisks', function ( t ) { + let tx = "Just some **** text\n\n\ +****\n\n\ +Some more text."; + t.is( textile.convert( tx ), + "

    Just some **** text

    \n\ +
    \n\ +

    Some more text.

    ", tx ); +}); + + +test( 'horizontal rule using dashes', function ( t ) { + let tx = "Just some --- text\n\n\ +---\n\n\ +Some more text."; + t.is( textile.convert( tx ), + "

    Just some --- text

    \n\ +
    \n\ +

    Some more text.

    ", tx ); +}); + + +test( 'horizontal rule using underscores', function ( t ) { + let tx = "Just some ___ text\n\n\ +___\n\n\ +Some more text."; + t.is( textile.convert( tx ), + "

    Just some ___ text

    \n\ +
    \n\ +

    Some more text.

    ", tx ); +}); + + +test( 'lang attribute cannot contain square brackets', function ( t ) { + let tx = "some @[[code]]@"; + t.is( textile.convert( tx ), + "

    some [[code]]

    ", tx ); +}); + + +test( 'pre blocks preserve leading whitespace', function ( t ) { + let tx = "pre. Text in a pre block\n\ +is displayed in a fixed-width\n\ + font. It preserves\n\ + s p a c e s, line breaks\n\ + and ascii bunnies."; + t.is( textile.convert( tx ), + "
         Text in a pre block\n\
    +is displayed in a fixed-width\n\
    +     font. It preserves\n\
    +  s p a c e s, line breaks\n\
    +     and ascii bunnies.
    ", tx ); +}); + + +test( 'code blocks preserve leading whitespace', function ( t ) { + let tx = "bc. false\n\ +} else {"; + t.is( textile.convert( tx ), + "
      false\n\
    +} else {
    ", tx ); +}); + + +test( 'citation ending with question mark', function ( t ) { + let tx = "??What the Story Morning Glory???"; + t.is( textile.convert( tx ), + "

    What the Story Morning Glory?

    ", tx ); +}); + + +test( 'citation including question mark', function ( t ) { + let tx = "??What's the Matter with Kansas? How Conservatives Won the Heart of America?? is a great book!"; + t.is( textile.convert( tx ), + "

    What’s the Matter with Kansas? How Conservatives Won the Heart of America is a great book!

    ", tx ); +}); + + +test( 'emphasized word including underscore', function ( t ) { + let tx = "_trythis_ it will keep the empahsis.\n\ +_and_this_too_ it should keep the emphasis but does not with redcloth."; + t.is( textile.convert( tx ), + "

    trythis it will keep the empahsis.
    \n\ +and_this_too it should keep the emphasis but does not with redcloth.

    ", tx ); +}); + + +test( 'code captures spaces when made explicit with square brackets', function ( t ) { + let tx = "Start a paragraph with [@p. @] (that's p, a period, and a space)."; + t.is( textile.convert( tx ), + "

    Start a paragraph with p. (that’s p, a period, and a space).

    ", tx ); +}); + + +test( 'unrecognized block starting with t not eaten', function ( t ) { + let tx = "tel. 0 700 123 123"; + t.is( textile.convert( tx ), + "

    tel. 0 700 123 123

    ", tx ); +}); + + +test( 'bolded number at start of phrase', function ( t ) { + let tx = "*22 watermelons* is my limit"; + t.is( textile.convert( tx ), + "

    22 watermelons is my limit

    ", tx ); +}); + + +test( 'bolded paragraph', function ( t ) { + let tx = "*- I would expect it to be a bolded paragraph.*"; + t.is( textile.convert( tx ), + "

    - I would expect it to be a bolded paragraph.

    ", tx ); +}); + diff --git a/test/block_comments.js b/test/block_comments.js index fc7d014..80305de 100644 --- a/test/block_comments.js +++ b/test/block_comments.js @@ -1,67 +1,41 @@ -test('Textile comments', function () { - - - -equal(textile.convert( // Textile comments - - "###. Here's a comment.\n"+ - "\n"+ - "h3. Hello\n"+ - "\n"+ - "###. And\n"+ - "another\n"+ - "one.\n"+ - "\n"+ - "Goodbye.\n" - -), // Should output - - "

    Hello

    \n"+ - "\n"+ - "

    Goodbye.

    " - -); - - -equal(textile.convert( // Textile comments - - "Some text here.\n"+ - "\n"+ - "###. This is a textile comment block.\n"+ - "It will be removed from your document.\n"+ - "\n"+ - "More text to follow.\n" - -), // Should output - - "

    Some text here.

    \n"+ - "\n"+ - "

    More text to follow.

    " - -); - - -equal(textile.convert( // Textile comments extended - - "Some text here.\n"+ - "\n"+ - "###.. This is a textile comment block.\n"+ - "It will be removed from your document.\n"+ - "\n"+ - "This is also a comment.\n"+ - "\n"+ - "p. More text to follow.\n" - -), // Should output - - "

    Some text here.

    \n"+ - "\n"+ - "

    More text to follow.

    " - -); - +import test from 'ava'; +import textile from '../src'; + +test( 'Textile comments', function ( t ) { + let tx = "###. Here's a comment.\n\n\ +h3. Hello\n\n\ +###. And\n\ +another\n\ +one.\n\n\ +Goodbye.\n\ +"; + t.is( textile.convert( tx ), + "

    Hello

    \n\n\ +

    Goodbye.

    ", tx ); +}); +test( 'Textile comments', function ( t ) { + let tx = "Some text here.\n\n\ +###. This is a textile comment block.\n\ +It will be removed from your document.\n\n\ +More text to follow.\n\ +"; + t.is( textile.convert( tx ), + "

    Some text here.

    \n\n\ +

    More text to follow.

    ", tx ); +}); +test( 'Textile comments extended', function ( t ) { + let tx = "Some text here.\n\n\ +###.. This is a textile comment block.\n\ +It will be removed from your document.\n\n\ +This is also a comment.\n\n\ +p. More text to follow.\n\ +"; + t.is( textile.convert( tx ), + "

    Some text here.

    \n\n\ +

    More text to follow.

    ", tx ); }); + diff --git a/test/code.js b/test/code.js new file mode 100644 index 0000000..b4a931f --- /dev/null +++ b/test/code.js @@ -0,0 +1,271 @@ +// code.yml +import test from 'ava'; +import textile from '../src'; + +test( 'inline code', function ( t ) { + let tx = "This is an empty dictionary: @{}@"; + t.is( textile.convert( tx ), + "

    This is an empty dictionary: {}

    ", tx ); +}); + + +// not PHP standard +/*test( 'inline snip', function ( t ) { + let tx = "The ```command``` is here."; + t.is( textile.convert( tx ), + "

    The

    command
    \n\ + is here.

    ", tx ); +});*/ + + +test( 'inline code escapement', function ( t ) { + let tx = "Please type @cat \"file.txt\" > otherfile.txt@ at the prompt."; + t.is( textile.convert( tx ), + "

    Please type cat \"file.txt\" > otherfile.txt at the prompt.

    ", tx ); +}); + + +test( 'inline code escapement with digits', function ( t ) { + let tx = "Regex-based string substitution with Ruby's gsub!: @\"123<789\".gsub!(/ \"123789\"@"; + t.is( textile.convert( tx ), + "

    Regex-based string substitution with Ruby’s gsub!: \"123<789\".gsub!(/</, \"\") => \"123789\"

    ", tx ); +}); + + +test( 'inlne code escapement describing textile paragraph styling ', function ( t ) { + let tx = "This paragraph is aligned left but if you add this: @p>.@ to the beginning it will be aligned right."; + t.is( textile.convert( tx ), + "

    This paragraph is aligned left but if you add this: p>. to the beginning it will be aligned right.

    ", tx ); +}); + + +test( 'escapes code snippet containing html tag', function ( t ) { + let tx = "At the top of each page, please put @

    Title

    @ in the HTML."; + t.is( textile.convert( tx ), + "

    At the top of each page, please put <h2>Title</h2> in the HTML.

    ", tx ); +}); + + +test( 'escaping in blockcode', function ( t ) { + let tx = "bc. This is within a block of code, so < and > should be entities. You can talk about a

    tag if you wish and it will be properly escaped."; + t.is( textile.convert( tx ), + "

    This is within a block of code, so < and > should be entities.  You can talk about a <p class=\"foo\"> tag if you wish and it will be properly escaped.
    ", tx ); +}); + + +test( 'escaping in pre', function ( t ) { + let tx = "
    This is within a block of code, so < and > should be entities.  You can talk about a 

    tag in pre tags too.

    "; + t.is( textile.convert( tx ), + "
    This is within a block of code, so < and > should be entities.  You can talk about a <p class=\"foo\"> tag in pre tags too.
    ", tx ); +}); + + +test( 'escaping in normal text', function ( t ) { + let tx = "This is a regular paragraph. AT&T. £38 > $38."; + t.is( textile.convert( tx ), + "

    This is a regular paragraph. AT&T. £38 > $38.

    ", tx ); +}); + + +test( 'preservation of existing entities', function ( t ) { + let tx = "Math fact: 3 < 5 & 5 > 3 but £6 > $6. Oh, and 2 ÷ 4 is ½."; + t.is( textile.convert( tx ), + "

    Math fact: 3 < 5 & 5 > 3 but £6 > $6. Oh, and 2 ÷ 4 is ½.

    ", tx ); +}); + + +test( 'escaping of existing entities in blockcode', function ( t ) { + let tx = "bc. Math fact: 3 < 5 & 5 > 3 but £5 > $5."; + t.is( textile.convert( tx ), + "
    Math fact: 3 &lt; 5 &amp; 5 &gt; 3 but &pound;5 &#62; $5.
    ", tx ); +}); + + +test( 'no formatting within pre', function ( t ) { + let tx = "
    \n\
    +\n\
    +# *test*\n\
    +__not italics__\n\
    +no hard breaks\n\
    +\n\
    +
    "; + t.is( textile.convert( tx ), + "
    \n\
    +\n\
    +# *test*\n\
    +__not italics__\n\
    +no hard breaks\n\
    +\n\
    +
    ", tx ); +}); + + +test( 'no formatting within blockcode', function ( t ) { + let tx = "bc. __not italics__"; + t.is( textile.convert( tx ), + "
    __not italics__
    ", tx ); +}); + + +test( 'double-equals as inline notextile', function ( t ) { + let tx = "p. Regular paragraph\n\n\ +==Escaped portion -- will not be formatted by Textile at all==\n\n\ +p. Back to normal."; + t.is( textile.convert( tx ), + "

    Regular paragraph

    \n\ +

    Escaped portion -- will not be formatted by Textile at all

    \n\ +

    Back to normal.

    ", tx ); +}); + + +test( 'notextile tags', function ( t ) { + let tx = "\n\ +# *test*\n\ +"; + t.is( textile.convert( tx ), + "# *test*", tx ); +}); + + +test( 'unfinished notextile tag', function ( t ) { + let tx = "\n\ +# *test*"; + t.is( textile.convert( tx ), + "

    \n\ +
      \n\ +\t
    1. test
    2. \n\ +
    ", tx ); +}); + + +test( 'unfinished script tag', function ( t ) { + let tx = "" - -), // Should output - - "" - -,"embedded javascript"); - - -// =[ 18 ]============================================================================== - - -equal(textile.convert( // The textile - - "Please email me at ." - -), // Should output - - "

    Please email me at .

    " - -,"inline embedded javascript"); - - -// =[ 19 ]============================================================================== - - -equal(textile.convert( // The textile - - "
    \n"+ - "This is a paragraph.\n"+ - "
    " - -), // Should output - - "
    \n"+ - "

    This is a paragraph.

    \n"+ - "
    " - -,"HTML end tag can end paragraph"); - - -// =[ 20 ]============================================================================== - - -equal(textile.convert( // The textile - - "
    \n"+ - "bq. This is a blockquote.\n"+ - "
    " - -), // Should output - - "
    \n"+ - "
    \n"+ - "

    This is a blockquote.

    \n"+ - "
    \n"+ - "
    " - -,"HTML end tag can end blockquote"); - - -// =[ 21 ]============================================================================== - - -equal(textile.convert( // The textile - - "
    \n"+ - "\n"+ - "h2. heading\n"+ - "\n"+ - "|a|b|c|\n"+ - "|d|e|f|" - -), // Should output - - "
    \n"+ - "

    heading

    \n"+ - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    abc
    def
    " - -,"before table does not affect table"); - - -// =[ 22 ]============================================================================== - - -equal(textile.convert( // The textile - - "http://foo.com/bar?something=1~2~3" - -), // Should output - - "

    http://foo.com/bar?something=1~2~3

    " - -,"tilde in innerHTML is not altered"); - - -// =[ 23 ]============================================================================== - - -equal(textile.convert( // The textile - - "
    " - -), // Should output - - "
    " - -,"empty block"); - - -// =[ 24 ]============================================================================== - -/* This HTML is broken - -equal(textile.convert( // The textile - - "

    " - -), // Should output - - "

    " - -,"objects in paragraphs are not modified"); -*/ - -// =[ 25 ]============================================================================== - - -equal(textile.convert( // The textile - - "
    some bold text
    " - -), // Should output - - "
    some <b>bold</b> text
    " - -,"in code escaped properly"); - - -// =[ 26 ]============================================================================== - - -equal(textile.convert( // The textile - - "
    some bold text
    " - -), // Should output - - "
    some <b>bold</b> text
    " - -,"in code with class attribute escaped properly"); - - -// =[ 27 ]============================================================================== - - -equal(textile.convert( // The textile - - "Sir Bobby Robson, is a famous footballer" - -), // Should output - - "

    Sir Bobby Robson, is a famous footballer

    " - -,"notextile beginning the line"); - - -// =[ 28 ]============================================================================== - - -equal(textile.convert( // The textile - - "br(clear). " - -), // Should output - - "
    " - -,"br tag with class"); - - -// =[ 29 ]============================================================================== - - -equal(textile.convert( // The textile - - "hr(clear). " - -), // Should output - - "
    " - -,"hr tag with class"); - - -}); - diff --git a/test/converted/images.js b/test/converted/images.js deleted file mode 100644 index 96c25e5..0000000 --- a/test/converted/images.js +++ /dev/null @@ -1,926 +0,0 @@ -test('images.yml', function () { - - -// =[ 1 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !image.jpg!" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 2 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !image.jpg(with alt text)!" - -), // Should output - - "

    This is an

    "); - - -// =[ 3 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 4 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg#a1!" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 5 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !image.jpg!." - -), // Should output - - "

    This is an \"\".

    "); - - -// =[ 6 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !image.jpg(with alt text)!." - -), // Should output - - "

    This is an .

    "); - - -// =[ 7 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!." - -), // Should output - - "

    This is an \"\".

    "); - - -// =[ 8 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg#a1!." - -), // Should output - - "

    This is an \"\".

    "); - - -// =[ 9 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is not an image!!!" - -), // Should output - - "

    This is not an image!!!

    "); - - -// =[ 10 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is not an! image!" - -), // Should output - - "

    This is not an! image!

    "); - - -// =[ 11 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:#1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 12 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:#a" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 13 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:#a1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 14 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:#a10" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 15 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:index.html" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 16 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:index.html#1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 17 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:index.html#a1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 18 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:index.html#a10" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 19 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:index.html?foo=bar" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 20 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:index.html?foo=bar#1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 21 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:index.html?foo=bar#a" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 22 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:index.html?foo=bar#a1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 23 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:index.html?foo=bar#a10" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 24 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 25 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/#1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 26 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/#a" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 27 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/#a1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 28 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/#a10" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 29 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 30 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html#1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 31 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html#a" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 32 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html#a1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 33 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html#a10" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 34 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 35 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar#1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 36 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar#a" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 37 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar#a1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 38 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar#a10" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 39 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 40 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 41 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 42 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a1" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 43 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a10" - -), // Should output - - "

    This is an \"\"

    "); - - -// =[ 44 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b." - -), // Should output - - "

    This is an \"\".

    "); - - -// =[ 45 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#1." - -), // Should output - - "

    This is an \"\".

    "); - - -// =[ 46 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a." - -), // Should output - - "

    This is an \"\".

    "); - - -// =[ 47 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a1." - -), // Should output - - "

    This is an \"\".

    "); - - -// =[ 48 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a10." - -), // Should output - - "

    This is an \"\".

    "); - - -// =[ 49 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b, but this is not." - -), // Should output - - "

    This is an \"\", but this is not.

    "); - - -// =[ 50 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#1, but this is not." - -), // Should output - - "

    This is an \"\", but this is not.

    "); - - -// =[ 51 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a, but this is not." - -), // Should output - - "

    This is an \"\", but this is not.

    "); - - -// =[ 52 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a1, but this is not." - -), // Should output - - "

    This is an \"\", but this is not.

    "); - - -// =[ 53 ]============================================================================== - - -equal(textile.convert( // The textile - - "(This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a10) This is not." - -), // Should output - - "

    (This is an \"\") This is not.

    "); - - -// =[ 54 ]============================================================================== - - -equal(textile.convert( // The textile - - "(This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b) This is not." - -), // Should output - - "

    (This is an \"\") This is not.

    "); - - -// =[ 55 ]============================================================================== - - -equal(textile.convert( // The textile - - "(This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#1) This is not." - -), // Should output - - "

    (This is an \"\") This is not.

    "); - - -// =[ 56 ]============================================================================== - - -equal(textile.convert( // The textile - - "(This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a) This is not." - -), // Should output - - "

    (This is an \"\") This is not.

    "); - - -// =[ 57 ]============================================================================== - - -equal(textile.convert( // The textile - - "(This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a1) This is not." - -), // Should output - - "

    (This is an \"\") This is not.

    "); - - -// =[ 58 ]============================================================================== - - -equal(textile.convert( // The textile - - "(This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a10) This is not." - -), // Should output - - "

    (This is an \"\") This is not.

    "); - - -// =[ 59 ]============================================================================== - - -equal(textile.convert( // The textile - - "!../../image.jpg!" - -), // Should output - - "

    \"\"

    " - -,"image with relative src with dot"); - - -// =[ 60 ]============================================================================== - - -equal(textile.convert( // The textile - - "!(myclass)image.jpg!" - -), // Should output - - "

    \"\"

    " - -,"image with class"); - - -// =[ 61 ]============================================================================== - - -equal(textile.convert( // The textile - - "!(myclass). image.jpg!" - -), // Should output - - "

    \"\"

    " - -,"image with class and dotspace"); - - -// =[ 62 ]============================================================================== - - -equal(textile.convert( // The textile - - "!(myclass)../../image.jpg!" - -), // Should output - - "

    \"\"

    " - -,"image with class and relative src with dots"); - - -// =[ 63 ]============================================================================== - - -equal(textile.convert( // The textile - - "!(myclass). ../../image.jpg!" - -), // Should output - - "

    \"\"

    " - -,"image with class and dotspace and relative src with dots"); - - -// =[ 64 ]============================================================================== - - -equal(textile.convert( // The textile - - "!{color:red}image.jpg!" - -), // Should output - - "

    \"\"

    " - -,"image with style"); - - -// =[ 65 ]============================================================================== - - -equal(textile.convert( // The textile - - "!{color:red}. image.jpg!" - -), // Should output - - "

    \"\"

    " - -,"image with style and dotspace"); - - -// =[ 66 ]============================================================================== - - -equal(textile.convert( // The textile - - "!/pictures/cat_and_fox.jpg(Trady Blix & The cartoon fox)!" - -), // Should output - - "

    \"Trady

    " - -,"image attributes has ampersand html entity in alt and title"); - - -// =[ 67 ]============================================================================== - - -equal(textile.convert( // The textile - - "!/pictures/bacon.jpg(The fox said: \"Have some chunky bacon\")!" - -), // Should output - - "

    \"The

    " - -,"image attributes has double quote html entity in alt and title"); - - -// =[ 68 ]============================================================================== - - -equal(textile.convert( // The textile - - "!/pictures/bacon.jpg(The fox said: 'Have some chunky bacon')!" - -), // Should output - - "

    \"The

    " - -,"image attributes has single quote html entity in alt and title"); - - -// =[ 69 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an [!image.jpg!] you see." - -), // Should output - - "

    This is an \"\" you see.

    " - -,"in square brackets"); - - -// =[ 70 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is an [!image.jpg!:http://example.com/] you see." - -), // Should output - - "

    This is an \"\" you see.

    " - -,"with link in square brackets"); - - -// =[ 71 ]============================================================================== - - -equal(textile.convert( // The textile - - "!http://commons.wikimedia.org/wiki/File:Rubis_sur_calcite_2(Vietnam).jpg!" - -), // Should output - - "

    \"\"

    " - -,"url containing parentheses"); - - -// =[ 72 ]============================================================================== - - -equal(textile.convert( // The textile - - "!http://commons.wikimedia.org/wiki/File:Rubis_sur_calcite_2(Vietnam).jpg(a big rock)!" - -), // Should output - - "

    \"a

    " - -,"with alt and url containing parentheses"); - - -// =[ 73 ]============================================================================== - - -equal(textile.convert( // The textile - - "!image.jpg(Alt text with (parentheses).)!" - -), // Should output - - "

    \"Alt

    " - -,"with link that contains parentheses"); - - -// =[ 74 ]============================================================================== - - -equal(textile.convert( // The textile - - "!/image_r.jpg(description)!:image.jpg text." - -), // Should output - - "

    \"description\" text.

    "+ - "" - -,"with link and title and text afterward"); - - -}); - diff --git a/test/converted/instiki.js b/test/converted/instiki.js deleted file mode 100644 index d6ecf90..0000000 --- a/test/converted/instiki.js +++ /dev/null @@ -1,102 +0,0 @@ -test('instiki.yml', function () { - - -// =[ 1 ]============================================================================== - - -equal(textile.convert( // The textile - - "_Hi, Joe Bob?, this should all be in italic!_" - -), // Should output - - "

    Hi, Joe Bob?, this should all be in italic!

    "); - - -// =[ 2 ]============================================================================== - - -equal(textile.convert( // The textile - - "*this span is strong*" - -), // Should output - - "

    this span is strong

    "); - - -// =[ 3 ]============================================================================== - - -equal(textile.convert( // The textile - - "*this Camel Thing? is strong*" - -), // Should output - - "

    this Camel Thing? is strong

    "); - - -// =[ 4 ]============================================================================== - - -equal(textile.convert( // The textile - - "_this span is italic_" - -), // Should output - - "

    this span is italic

    "); - - -// =[ 5 ]============================================================================== - - -equal(textile.convert( // The textile - - "%{color:red}nested span because of Camel Word?%" - -), // Should output - - "

    nested span because of Camel Word?

    "); - - -// =[ 6 ]============================================================================== - - -equal(textile.convert( // The textile - - "h2. Version History\n"+ - "\n"+ - "* \"Version\n"+ - "0.0\":http://www.threewordslong.com/render-0-8-9b.patch - Early version using MD5 hashes.\n"+ - "* \"Version\n"+ - "0.1\":http://www.threewordslong.com/chunk-0-1.patch.gz - First cut of new system. Much cleaner.\n"+ - "* \"Version 0.2\":http://www.threewordslong.com/chunk-0-2.patch.gz - Fixed problem with \"authors\" page and some tests." - -), // Should output - - "

    Version History

    \n"+ - ""); - - -// =[ 7 ]============================================================================== - - -equal(textile.convert( // The textile - - "--richSeymour --whyTheLuckyStiff" - -), // Should output - - "

    —richSeymour —whyTheLuckyStiff

    "); - - -}); - diff --git a/test/converted/links.js b/test/converted/links.js deleted file mode 100644 index cb56c9a..0000000 --- a/test/converted/links.js +++ /dev/null @@ -1,1019 +0,0 @@ -test('links.yml', function () { - - -// =[ 1 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":#1" - -), // Should output - - "

    link text

    "); - - -// =[ 2 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":#a" - -), // Should output - - "

    link text

    "); - - -// =[ 3 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":#a1" - -), // Should output - - "

    link text

    "); - - -// =[ 4 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":#a10" - -), // Should output - - "

    link text

    "); - - -// =[ 5 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":index.html" - -), // Should output - - "

    link text

    "); - - -// =[ 6 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":index.html#1" - -), // Should output - - "

    link text

    "); - - -// =[ 7 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":index.html#a" - -), // Should output - - "

    link text

    "); - - -// =[ 8 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":index.html#a1" - -), // Should output - - "

    link text

    "); - - -// =[ 9 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":index.html#a10" - -), // Should output - - "

    link text

    "); - - -// =[ 10 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/" - -), // Should output - - "

    link text

    "); - - -// =[ 11 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/#1" - -), // Should output - - "

    link text

    "); - - -// =[ 12 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/#a" - -), // Should output - - "

    link text

    "); - - -// =[ 13 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/#a1" - -), // Should output - - "

    link text

    "); - - -// =[ 14 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/#a10" - -), // Should output - - "

    link text

    "); - - -// =[ 15 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/index.html" - -), // Should output - - "

    link text

    "); - - -// =[ 16 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/index.html#a" - -), // Should output - - "

    link text

    "); - - -// =[ 17 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/index.html#1" - -), // Should output - - "

    link text

    "); - - -// =[ 18 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/index.html#a1" - -), // Should output - - "

    link text

    "); - - -// =[ 19 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/index.html#a10" - -), // Should output - - "

    link text

    "); - - -// =[ 20 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/?foo=bar" - -), // Should output - - "

    link text

    "); - - -// =[ 21 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/?foo=bar#a" - -), // Should output - - "

    link text

    "); - - -// =[ 22 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link & text\":http://example.com/?foo=bar#a" - -), // Should output - - "

    link & text

    "); - - -// =[ 23 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/?foo=bar#1" - -), // Should output - - "

    link text

    "); - - -// =[ 24 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/?foo=bar#a1" - -), // Should output - - "

    link text

    "); - - -// =[ 25 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/?foo=bar#a10" - -), // Should output - - "

    link text

    "); - - -// =[ 26 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/?foo=bar&a=b" - -), // Should output - - "

    link text

    "); - - -// =[ 27 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/?foo=bar&a=b#1" - -), // Should output - - "

    link text

    "); - - -// =[ 28 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/?foo=bar&a=b#a" - -), // Should output - - "

    link text

    "); - - -// =[ 29 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/?foo=bar&a=b#a1" - -), // Should output - - "

    link text

    "); - - -// =[ 30 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/?foo=bar&a=b#a10" - -), // Should output - - "

    link text

    "); - - -// =[ 31 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/" - -), // Should output - - "

    This is a link

    "); - - -// =[ 32 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/." - -), // Should output - - "

    This is a link.

    "); - - -// =[ 33 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/index.html." - -), // Should output - - "

    This is a link.

    "); - - -// =[ 34 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/index.html#a." - -), // Should output - - "

    This is a link.

    "); - - -// =[ 35 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/index.html#1." - -), // Should output - - "

    This is a link.

    "); - - -// =[ 36 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/index.html#a1." - -), // Should output - - "

    This is a link.

    "); - - -// =[ 37 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/index.html#a10." - -), // Should output - - "

    This is a link.

    "); - - -// =[ 38 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/?foo=bar." - -), // Should output - - "

    This is a link.

    "); - - -// =[ 39 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/?foo=bar#1." - -), // Should output - - "

    This is a link.

    "); - - -// =[ 40 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/?foo=bar#a." - -), // Should output - - "

    This is a link.

    "); - - -// =[ 41 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/?foo=bar#a1." - -), // Should output - - "

    This is a link.

    "); - - -// =[ 42 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/?foo=bar#a10." - -), // Should output - - "

    This is a link.

    "); - - -// =[ 43 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a \"link\":http://example.com/?foo=bar#a10, but this is not." - -), // Should output - - "

    This is a link, but this is not.

    "); - - -// =[ 44 ]============================================================================== - - -equal(textile.convert( // The textile - - "(This is a \"link\":http://example.com/?foo=bar#a10) but this is not." - -), // Should output - - "

    (This is a link) but this is not.

    "); - - -// =[ 45 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text(link title)\":http://example.com/" - -), // Should output - - "

    link text

    "); - - -// =[ 46 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"(link) text(link title)\":http://example.com/" - -), // Should output - - "

    text

    " - -,"link with title attribute"); - - -// =[ 47 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"text (link title)\":http://example.com/" - -), // Should output - - "

    text

    " - -,"link with space between link text and title attribute"); - - -// =[ 48 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"Dive Into XML\":http://www.xml.com/pub/au/164" - -), // Should output - - "

    Dive Into XML

    "); - - -// =[ 49 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"Lab Exercises\":../lab/exercises/exercises.html." - -), // Should output - - "

    Lab Exercises.

    "); - - -// =[ 50 ]============================================================================== - - -equal(textile.convert( // The textile - - "Go to \"discuss\":http://www.dreammoods.com/cgibin/cutecast/cutecast.pl?forum=1&thread=26627 to discuss." - -), // Should output - - "

    Go to discuss to discuss.

    "); - - -// =[ 51 ]============================================================================== - - -equal(textile.convert( // The textile - - "* \"rubylang\":http://www.ruby-lang.org/en/" - -), // Should output - - ""); - - -// =[ 52 ]============================================================================== - - -equal(textile.convert( // The textile - - "The ION coding style document found at \"IONCodingStyleGuide.doc\":http://perforce:8081/@md=d&cd=//&c=82E@//depot/systest/system/main/pub/doc/IONCodingStyleGuide.doc?ac=22 codifies a couple of rules to ensure reasonably consistent code and documentation of libraries in ION. Test text" - -), // Should output - - "

    The ION coding style document found at IONCodingStyleGuide.doc codifies a couple of rules to ensure reasonably consistent code and documentation of libraries in ION. Test text

    "); - - -// =[ 53 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"testing\":" - -), // Should output - - "

    “testing”:

    "); - - -// =[ 54 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"Link\":/foo.html me" - -), // Should output - - "

    Link me

    " - -,"trailing space not absorbed by link"); - - -// =[ 55 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"Link\":/foo.html, me" - -), // Should output - - "

    Link, me

    " - -,"trailing comma stays outside link"); - - -// =[ 56 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"Link\":/foo.html! me" - -), // Should output - - "

    Link! me

    " - -,"trailing exclamation stays outside link"); - - -// =[ 57 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"Link\":/foo.html; me" - -), // Should output - - "

    Link; me

    " - -,"trailing semicolon stays outside link"); - - -// =[ 58 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"Link\":/foo.html." - -), // Should output - - "

    Link.

    " - -,"trailing period stays outside link"); - - -// =[ 59 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"(just in case you were wondering)\":http://slashdot.org/" - -), // Should output - - "

    (just in case you were wondering)

    " - -,"whose text is a parenthetical statement"); - - -// =[ 60 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"(myclass) (just in case you were wondering)\":http://slashdot.org/" - -), // Should output - - "

    (just in case you were wondering)

    " - -,"that has a class and whose text is a parenthetical statement"); - - -// =[ 61 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"It is (very) fortunate that this works\":http://slashdot.org/" - -), // Should output - - "

    It is (very) fortunate that this works

    " - -,"link containing parentheses"); - - -// =[ 62 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"He said it is \"very unlikely\" this works\":http://slashdot.org/" - -), // Should output - - "

    He said it is “very unlikely” this works

    " - -,"link containing quotes"); - - -// =[ 63 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"He said it is \"very unlikely\" the \"economic stimulus\" works\":http://slashdot.org/" - -), // Should output - - "

    He said it is “very unlikely” the “economic stimulus” works

    " - -,"link containing multiple quotes"); - - -// =[ 64 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"\"Open the pod bay doors please, HAL.\"\":http://www.youtube.com/watch?v=npN9l2Bd06s" - -), // Should output - - "

    “Open the pod bay doors please, HAL.”

    " - -,"linked quoted phrase"); - - -// =[ 65 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"quote\" text \"quote\" text \"link\":http://google.com" - -), // Should output - - "

    “quote” text “quote” text link

    " - -,"link following quoted phrase"); - - -// =[ 66 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a link to a \"Wikipedia article about Barack\":http://en.wikipedia.org/wiki/Barack_Obama" - -), // Should output - - "

    This is a link to a Wikipedia article about Barack

    " - -,"links containing underscores"); - - -// =[ 67 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a link to a [\"Wikipedia article about Textile\":http://en.wikipedia.org/wiki/Textile_(markup_language)]" - -), // Should output - - "

    This is a link to a Wikipedia article about Textile

    " - -,"links containing parentheses"); - - -// =[ 68 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a regular link (but in parentheses: \"Google\":http://www.google.com)" - -), // Should output - - "

    This is a regular link (but in parentheses: Google)

    " - -,"links contained in parentheses"); - - -// =[ 69 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a link to a \"Wikipedia article about Textile\":http://en.wikipedia.org/wiki/Textile_(markup_language)" - -), // Should output - - "

    This is a link to a Wikipedia article about Textile

    " - -,"links containing parentheses without brackets"); - - -// =[ 70 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a link to a \"Wikipedia article about Textile\":http://en.wikipedia.org/wiki/Textile_(markup_language)." - -), // Should output - - "

    This is a link to a Wikipedia article about Textile.

    " - -,"links containing parentheses period at end without brackets"); - - -// =[ 71 ]============================================================================== - - -equal(textile.convert( // The textile - - "This is a link to a \"Wikipedia article about Textile\":http://en.wikipedia.org/wiki/Textile_(markup_language" - -), // Should output - - "

    This is a link to a Wikipedia article about Textile

    " - -,"broken links containing parentheses without brackets"); - - -// =[ 72 ]============================================================================== - - -equal(textile.convert( // The textile - - "Textile is awesome! (Check out the \"Wikipedia article about Textile\":http://en.wikipedia.org/wiki/Textile_(markup_language))" - -), // Should output - - "

    Textile is awesome! (Check out the Wikipedia article about Textile)

    " - -,"links containing parentheses without brackets inside a parenthesis"); - - -// =[ 73 ]============================================================================== - - -equal(textile.convert( // The textile - - "Some \"text\" followed by a \"link\":http://redcloth.org." - -), // Should output - - "

    Some “text” followed by a link.

    " - -,"quotes and follow link"); - - -// =[ 74 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link\":google-rocks\n"+ - "\n"+ - "[google-rocks]http://google.com" - -), // Should output - - "

    link

    " - -,"link alias containing dashes"); - - -// =[ 75 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"I first learned about \"Redcloth\":http://redcloth.org/ several years ago.\n"+ - "\n"+ - "\"It's wonderful.\"" - -), // Should output - - "

    “I first learned about Redcloth several years ago.

    \n"+ - "

    “It’s wonderful.”

    " - -,"contained in multi-paragraph quotes"); - - -// =[ 76 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"Here is a link.\n"+ - "\n"+ - "\"I like links.\"" - -), // Should output - - "

    “Here is a link.

    \n"+ - "

    “I like links.”

    " - -,"as html in notextile contained in multi-paragraph quotes"); - - -// =[ 77 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"My wife, Tipper, and I will donate 100% of the proceeds of the award to the \"Alliance For Climate Protection\":http://www.looktothestars.org/charity/638-alliance-for-climate-protection,\" said Gore in an email. \"I am deeply honored to receive the Nobel Peace Prize.\"" - -), // Should output - - "

    “My wife, Tipper, and I will donate 100% of the proceeds of the award to the Alliance For Climate Protection,” said Gore in an email. “I am deeply honored to receive the Nobel Peace Prize.”

    " - -,"contained in para with multiple quotes"); - - -// =[ 78 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"British Skin Foundation (BSF)\":http://www.britishskinfoundation.org.uk" - -), // Should output - - "

    British Skin Foundation

    " - -,"with caps in the title"); - - -// =[ 79 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"\"Apply*apply online*\":/admissions/apply/" - -), // Should output - - "

    \"Applyapply online

    " - -,"containing HTML tags with quotes"); - - -}); - diff --git a/test/converted/lists.js b/test/converted/lists.js deleted file mode 100644 index 6ae5762..0000000 --- a/test/converted/lists.js +++ /dev/null @@ -1,790 +0,0 @@ -test('lists.yml', function () { - - -// =[ 1 ]============================================================================== - - -equal(textile.convert( // The textile - - "* command run: @time ruby run-tests.rb > toto@" - -), // Should output - - "
      \n"+ - "\t
    • command run: time ruby run-tests.rb > toto
    • \n"+ - "
    " - -,"code in bullet list"); - - -// =[ 2 ]============================================================================== - - -equal(textile.convert( // The textile - - "* first line\n"+ - "* second\n"+ - " line\n"+ - "* third line" - -), // Should output - - "
      \n"+ - "\t
    • first line
    • \n"+ - "\t
    • second
      \n"+ - "line
    • \n"+ - "\t
    • third line
    • \n"+ - "
    " - -,"hard break in list"); - - -// =[ 3 ]============================================================================== - - -equal(textile.convert( // The textile - - "* bullet\n"+ - "*# number\n"+ - "*# number\n"+ - "*#* bullet\n"+ - "*# number\n"+ - "*# number with\n"+ - "a break\n"+ - "* bullet\n"+ - "** okay" - -), // Should output - - "
      \n"+ - "\t
    • bullet\n"+ - "\t
        \n"+ - "\t\t
      1. number
      2. \n"+ - "\t\t
      3. number\n"+ - "\t\t
          \n"+ - "\t\t\t
        • bullet
        • \n"+ - "\t\t
      4. \n"+ - "\t\t
      5. number
      6. \n"+ - "\t\t
      7. number with
        \n"+ - "a break
      8. \n"+ - "\t
    • \n"+ - "\t
    • bullet\n"+ - "\t
        \n"+ - "\t\t
      • okay
      • \n"+ - "\t
    • \n"+ - "
    " - -,"mixed nesting"); - - -// =[ 4 ]============================================================================== - - -equal(textile.convert( // The textile - - "# one\n"+ - "# two\n"+ - "# three\n"+ - "\n"+ - "# one\n"+ - "# two\n"+ - "# three\n"+ - "\n"+ - "#_ four\n"+ - "# five\n"+ - "# six" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "\t
    3. two
    4. \n"+ - "\t
    5. three
    6. \n"+ - "
    \n"+ - "
      \n"+ - "\t
    1. one
    2. \n"+ - "\t
    3. two
    4. \n"+ - "\t
    5. three
    6. \n"+ - "
    \n"+ - "
      \n"+ - "\t
    1. four
    2. \n"+ - "\t
    3. five
    4. \n"+ - "\t
    5. six
    6. \n"+ - "
    " - -,"list continuation"); - - -// =[ 5 ]============================================================================== - - -equal(textile.convert( // The textile - - "# one\n"+ - "# two\n"+ - "# three\n"+ - "\n"+ - "test\n"+ - "\n"+ - "#_ four\n"+ - "# five\n"+ - "# six\n"+ - "\n"+ - "test\n"+ - "\n"+ - "#_ seven\n"+ - "# eight\n"+ - "# nine" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "\t
    3. two
    4. \n"+ - "\t
    5. three
    6. \n"+ - "
    \n"+ - "

    test

    \n"+ - "
      \n"+ - "\t
    1. four
    2. \n"+ - "\t
    3. five
    4. \n"+ - "\t
    5. six
    6. \n"+ - "
    \n"+ - "

    test

    \n"+ - "
      \n"+ - "\t
    1. seven
    2. \n"+ - "\t
    3. eight
    4. \n"+ - "\t
    5. nine
    6. \n"+ - "
    " - -,"continue after break"); - - -// =[ 6 ]============================================================================== - - -equal(textile.convert( // The textile - - "# one\n"+ - "# two\n"+ - "# three\n"+ - "\n"+ - "#_ four\n"+ - "# five\n"+ - "## sub-note\n"+ - "## another sub-note\n"+ - "# six\n"+ - "\n"+ - "#_ seven\n"+ - "# eight\n"+ - "# nine" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "\t
    3. two
    4. \n"+ - "\t
    5. three
    6. \n"+ - "
    \n"+ - "
      \n"+ - "\t
    1. four
    2. \n"+ - "\t
    3. five\n"+ - "\t
        \n"+ - "\t\t
      1. sub-note
      2. \n"+ - "\t\t
      3. another sub-note
      4. \n"+ - "\t
    4. \n"+ - "\t
    5. six
    6. \n"+ - "
    \n"+ - "
      \n"+ - "\t
    1. seven
    2. \n"+ - "\t
    3. eight
    4. \n"+ - "\t
    5. nine
    6. \n"+ - "
    " - -,"continue list when prior list contained nested list"); - - -// =[ 7 ]============================================================================== - - -equal(textile.convert( // The textile - - "#293 two ninety three\n"+ - "# two ninety four\n"+ - "# two ninety five\n"+ - "\n"+ - "#9 nine\n"+ - "# ten\n"+ - "# eleven" - -), // Should output - - "
      \n"+ - "\t
    1. two ninety three
    2. \n"+ - "\t
    3. two ninety four
    4. \n"+ - "\t
    5. two ninety five
    6. \n"+ - "
    \n"+ - "
      \n"+ - "\t
    1. nine
    2. \n"+ - "\t
    3. ten
    4. \n"+ - "\t
    5. eleven
    6. \n"+ - "
    " - -,"list start number"); - - -// =[ 8 ]============================================================================== - - -equal(textile.convert( // The textile - - "#9 nine\n"+ - "# ten\n"+ - "# eleven\n"+ - "\n"+ - "#_ twelve\n"+ - "# thirteen\n"+ - "# fourteen" - -), // Should output - - "
      \n"+ - "\t
    1. nine
    2. \n"+ - "\t
    3. ten
    4. \n"+ - "\t
    5. eleven
    6. \n"+ - "
    \n"+ - "
      \n"+ - "\t
    1. twelve
    2. \n"+ - "\t
    3. thirteen
    4. \n"+ - "\t
    5. fourteen
    6. \n"+ - "
    " - -,"continue list after started list"); - - -// =[ 9 ]============================================================================== - - -equal(textile.convert( // The textile - - "h2. End Notes\n"+ - "\n"+ - "# End Notes should be a numbered list\n"+ - "# Like this\n"+ - "# They must have anchors in the text\n"+ - "\n"+ - "h2. See Also\n"+ - "\n"+ - "* See Also notes should be bullets\n"+ - "* Like this\n"+ - "" - -), // Should output - - "

    End Notes

    \n"+ - "
      \n"+ - "\t
    1. End Notes should be a numbered list
    2. \n"+ - "\t
    3. Like this
    4. \n"+ - "\t
    5. They must have anchors in the text
    6. \n"+ - "
    \n"+ - "

    See Also

    \n"+ - "
      \n"+ - "\t
    • See Also notes should be bullets
    • \n"+ - "\t
    • Like this
    • \n"+ - "
    " - -,"end notes"); - - -// =[ 10 ]============================================================================== - - -equal(textile.convert( // The textile - - "A simple example.\n"+ - "# One\n"+ - "# Two" - -), // Should output - - "

    A simple example.

    \n"+ - "
      \n"+ - "\t
    1. One
    2. \n"+ - "\t
    3. Two
    4. \n"+ - "
    " - -,"ordered list immediately following paragraph"); - - -// =[ 11 ]============================================================================== - - -equal(textile.convert( // The textile - - "A simple example.\n"+ - "* One\n"+ - "* Two" - -), // Should output - - "

    A simple example.

    \n"+ - "
      \n"+ - "\t
    • One
    • \n"+ - "\t
    • Two
    • \n"+ - "
    " - -,"unordered list immediately following paragraph"); - - -// =[ 12 ]============================================================================== - - -equal(textile.convert( // The textile - - "div.. Here it comes.\n"+ - "\n"+ - "A simple example.\n"+ - "# One\n"+ - "# Two" - -), // Should output - - "
    Here it comes.
    \n"+ - "
    A simple example.
    \n"+ - "
      \n"+ - "\t
    1. One
    2. \n"+ - "\t
    3. Two
    4. \n"+ - "
    " - -,"ordered list immediately following extended block"); - - -// =[ 13 ]============================================================================== - - -equal(textile.convert( // The textile - - "div.. Here it comes.\n"+ - "\n"+ - "A simple example.\n"+ - "* One\n"+ - "* Two" - -), // Should output - - "
    Here it comes.
    \n"+ - "
    A simple example.
    \n"+ - "
      \n"+ - "\t
    • One
    • \n"+ - "\t
    • Two
    • \n"+ - "
    " - -,"unordered list immediately following extended block"); - - -// =[ 14 ]============================================================================== - -/* -equal(textile.convert( // The textile - - " * notice the leading space\n"+ - " * RedCloth 3.0.4 used to accept it\n"+ - " * Now we do too" - -), // Should output - - "
      \n"+ - "\t
    • notice the leading space
    • \n"+ - "\t
    • RedCloth 3.0.4 used to accept it
    • \n"+ - "\t
    • Now we do too
    • \n"+ - "
    " - -,"unordered list with leading spaces"); -*/ - -// =[ 15 ]============================================================================== - -/* -equal(textile.convert( // The textile - - " # notice the leading space\n"+ - " # RedCloth 3.0.4 used to accept it\n"+ - " # Now we do too" - -), // Should output - - "
      \n"+ - "\t
    1. notice the leading space
    2. \n"+ - "\t
    3. RedCloth 3.0.4 used to accept it
    4. \n"+ - "\t
    5. Now we do too
    6. \n"+ - "
    " - -,"ordered list with leading spaces"); -*/ - -// =[ 16 ]============================================================================== - - -equal(textile.convert( // The textile - - "*(class-one) one\n"+ - "*(class-two) two\n"+ - "*(class-three) three" - -), // Should output - - "
      \n"+ - "\t
    • one
    • \n"+ - "\t
    • two
    • \n"+ - "\t
    • three
    • \n"+ - "
    " - -,"unordered with classes"); - - -// =[ 17 ]============================================================================== - - -equal(textile.convert( // The textile - - "*< one\n"+ - "*> two\n"+ - "*<> three\n"+ - "*= four" - -), // Should output - - "
      \n"+ - "\t
    • one
    • \n"+ - "\t
    • two
    • \n"+ - "\t
    • three
    • \n"+ - "\t
    • four
    • \n"+ - "
    " - -,"unordered with alignments"); - - -// =[ 18 ]============================================================================== - - -equal(textile.convert( // The textile - - "#(class#id) one\n"+ - "# two\n"+ - "# three" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "\t
    3. two
    4. \n"+ - "\t
    5. three
    6. \n"+ - "
    " - -,"with attributes that apply to the whole list"); - - -// =[ 19 ]============================================================================== - - -equal(textile.convert( // The textile - - "#(#my-id) one\n"+ - "# two\n"+ - "# three" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "\t
    3. two
    4. \n"+ - "\t
    5. three
    6. \n"+ - "
    " - -,"with id on the list"); - - -// =[ 20 ]============================================================================== - - -equal(textile.convert( // The textile - - "#(my-class) one\n"+ - "# two\n"+ - "# three" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "\t
    3. two
    4. \n"+ - "\t
    5. three
    6. \n"+ - "
    " - -,"with class on the list"); - - -// =[ 21 ]============================================================================== - - -equal(textile.convert( // The textile - - "# one\n"+ - "#(#my-item) two\n"+ - "# three" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "\t
    3. two
    4. \n"+ - "\t
    5. three
    6. \n"+ - "
    " - -,"with id on the list item"); - - -// =[ 22 ]============================================================================== - - -equal(textile.convert( // The textile - - "#.\n"+ - "#(class#id) one\n"+ - "# two\n"+ - "# three" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "\t
    3. two
    4. \n"+ - "\t
    5. three
    6. \n"+ - "
    " - -,"with attributes that apply to the first list item"); - - -// =[ 23 ]============================================================================== - - -equal(textile.convert( // The textile - - "#{color:blue}.\n"+ - "# one\n"+ - "# two\n"+ - "# three" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "\t
    3. two
    4. \n"+ - "\t
    5. three
    6. \n"+ - "
    " - -,"changed from textism basics"); - - -// =[ 24 ]============================================================================== - - -equal(textile.convert( // The textile - - "#(class#id).\n"+ - "#(first) Item 1\n"+ - "#(second) Item 2\n"+ - "#(third) Item 3" - -), // Should output - - '
      \n'+ - '\t
    1. Item 1
    2. \n'+ - '\t
    3. Item 2
    4. \n'+ - '\t
    5. Item 3
    6. \n'+ - '
    ' - -,"item and list attributes"); - - -// =[ 25 ]============================================================================== - - -equal(textile.convert( // The textile - - "#( one" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "
    " - -,"with one padding-left increment"); - - -// =[ 26 ]============================================================================== - -/* -// PHP doesn't really allow padding on list items so let's not get into nuances here -equal(textile.convert( // The textile - - "#((myclass) one" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "
    " - -,"with one padding-left increment and class"); -*/ - -// =[ 27 ]============================================================================== - - -equal(textile.convert( // The textile - - "#(( two" - -), // Should output - - "
      \n"+ - "\t
    1. two
    2. \n"+ - "
    " - -,"with two padding-left increments"); - - -// =[ 28 ]============================================================================== - - -equal(textile.convert( // The textile - - "#) one" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "
    " - -,"with one padding-right increment"); - - -// =[ 29 ]============================================================================== - - -equal(textile.convert( // The textile - - "#() two" - -), // Should output - - "
      \n"+ - "\t
    1. two
    2. \n"+ - "
    " - -,"with padding-left and padding-right increments"); - - -// =[ 30 ]============================================================================== - - -equal(textile.convert( // The textile - - "#)( two" - -), // Should output - - "
      \n"+ - "\t
    1. two
    2. \n"+ - "
    " - -,"with padding-left and padding-right increments switched"); - - -// =[ 31 ]============================================================================== - -/* -// PHP doesn't really allow padding on list items so let's not get into nuances here -equal(textile.convert( // The textile - - "#()(myclass) two" - -), // Should output - - "
      \n"+ - "\t
    1. two
    2. \n"+ - "
    \n"+ - "" - -,"with padding-left and padding-right increments and class"); -*/ - - -// =[ 32 ]============================================================================== - - -equal(textile.convert( // The textile - - "# one\n"+ - "# two\n"+ - "#.\n"+ - "# tree" - -), // Should output - - "
      \n"+ - "\t
    1. one
    2. \n"+ - "\t
    3. two
    4. \n"+ - "\t
    5. tree
    6. \n"+ - "
    " - -,"list control items occuring-mid list should be ignored"); - - -// =[ 33 ]============================================================================== - - -equal(textile.convert( // The textile - -'#(class#id).\n'+ -'#(first) Item 1\n'+ -'##.\n'+ -'##(sub1) Sub item 1\n'+ -'## Sub item 2\n'+ -'#(second) Item 2\n'+ -'##_(sub3) Sub item 3\n'+ -'## Sub item 4\n'+ -'\n'+ -'#_(third) Item 3\n'+ -'##_(sub5) Sub item 5\n'+ -'## Sub item 6' - -), // Should output - -'
      \n'+ -'\t
    1. Item 1\n'+ -'\t
        \n'+ -'\t\t
      1. Sub item 1
      2. \n'+ -'\t\t
      3. Sub item 2
      4. \n'+ -'\t
    2. \n'+ -'\t
    3. Item 2\n'+ -'\t
        \n'+ -'\t\t
      1. Sub item 3
      2. \n'+ -'\t\t
      3. Sub item 4
      4. \n'+ -'\t
    4. \n'+ -'
    \n'+ -'
      \n'+ -'\t
    1. Item 3\n'+ -'\t
        \n'+ -'\t\t
      1. Sub item 5
      2. \n'+ -'\t\t
      3. Sub item 6
      4. \n'+ -'\t
    2. \n'+ -'
    ' - -,"complicated case with continues and classes"); - - -}); - diff --git a/test/converted/poignant.js b/test/converted/poignant.js deleted file mode 100644 index 1be7009..0000000 --- a/test/converted/poignant.js +++ /dev/null @@ -1,88 +0,0 @@ -test('poignant.yml', function () { - - -// =[ 1 ]============================================================================== - - -equal(textile.convert( // The textile - - "h3. False\n"+ - "\n"+ - "!\n" + - " if plastic_cup\n" + - " print \"Plastic cup is on the up 'n' up!\"\n" + - " end\n" + - "\n" + - "\n" + - "If @plastic_cup@ contains either @nil@ or @false@, you won't see anything print " + - "to the screen. They're not on the @if@ guest list. So @if@ isn't going to run " + - "any of the code it's protecting.\n" + - "\n" + - "But @nil@ and @false@ need not walk away in shame. They may be of questionable " + - "character, but @unless@ runs a smaller establishment that caters to the bedraggled. " + - "The @unless@ keyword has a policy of only allowing those with a negative charge in. " + - "Who are: @nil@ and @false@.\n" + - "\n" + - "
    \n" +
    -  "  unless plastic_cup\n" +
    -  "    print \"Plastic cup is on the down low.\"\n" +
    -  "  end\n" +
    -  "
    \n" + - "\n" + - "You can also use @if@ and @unless@ at the end of a single line of code, if that's " + - "all that is being protected.\n" + - "\n" + - "
    \n" +
    -  "  print \"Yeah, plastic cup is up again!\" if plastic_cup\n" +
    -  "  print \"Hardly. It's down.\" unless plastic_cup\n" +
    -  "
    \n" + - "\n" + - "Now that you've met @false@, I'm sure you can see what's on next." - -), // Should output - - "

    False

    \n"+ - "

    \"Shape

    \n"+ - "

    The cat Trady Blix. Frozen in emptiness. Immaculate whiskers rigid. Placid eyes of lake. Tail of warm icicle. Sponsored by a Very Powerful Pause Button.

    \n"+ - "

    The darkness surrounding Blix can be called negative space. Hang on to that phrase. Let it suggest that the emptiness has a negative connotation. In a similar way, nil has a slightly sour note that it whistles.

    \n"+ - "

    Generally speaking, everything in Ruby has a positive charge to it. This spark flows through strings, numbers, regexps, all of it. Only two keywords wear a shady cloak: nil and false draggin us down.

    \n"+ - "

    You can test that charge with an if keyword. It looks very much like the do blocks we saw in the last chapter, in that both end with an end.

    \n"+ - "
    \n"+
    -  "  if plastic_cup\n"+
    -  "    print \"Plastic cup is on the up 'n' up!\"\n"+
    -  "  end\n"+
    -  "
    \n"+ - "

    If plastic_cup contains either nil or false, you won’t see anything print to the screen. They’re not on the if guest list. So if isn’t going to run any of the code it’s protecting.

    \n"+ - "

    But nil and false need not walk away in shame. They may be of questionable character, but unless runs a smaller establishment that caters to the bedraggled. The unless keyword has a policy of only allowing those with a negative charge in. Who are: nil and false.

    \n"+ - "
    \n"+
    -  "  unless plastic_cup\n"+
    -  "    print \"Plastic cup is on the down low.\"\n"+
    -  "  end\n"+
    -  "
    \n"+ - "

    You can also use if and unless at the end of a single line of code, if that’s all that is being protected.

    \n"+ - "
    \n"+
    -  "  print \"Yeah, plastic cup is up again!\" if plastic_cup\n"+
    -  "  print \"Hardly. It's down.\" unless plastic_cup\n"+
    -  "
    \n"+ - "

    Now that you’ve met false, I’m sure you can see what’s on next.

    " -); - - -}); - diff --git a/test/converted/table.js b/test/converted/table.js deleted file mode 100644 index 2ef1133..0000000 --- a/test/converted/table.js +++ /dev/null @@ -1,526 +0,0 @@ -test('table.yml', function () { - - -// =[ 1 ]============================================================================== - - -equal(textile.convert( // The textile - - "|a|b|c|\n"+ - "|1|2|3|\n"+ - "\n"+ - "h3. A header after the table" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    abc
    123
    \n"+ - "

    A header after the table

    "); - - -// =[ 2 ]============================================================================== - - -equal(textile.convert( // The textile - - "|_. a|_. b|_. c|\n"+ - "|1|2|3|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    abc
    123
    "); - - -// =[ 3 ]============================================================================== - - -equal(textile.convert( // The textile - - "|This|is|a|simple|table|\n"+ - "|This|is|a|simple|row|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    Thisisasimpletable
    Thisisasimplerow
    "); - - -// =[ 4 ]============================================================================== - - -equal(textile.convert( // The textile - - "table{border:1px solid black}.\n"+ - "|This|is|a|row|\n"+ - "|This|is|a|row|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    Thisisarow
    Thisisarow
    "); - - -// =[ 5 ]============================================================================== - - -equal(textile.convert( // The textile - - "{background:#ddd}. |This|is|a|row|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    Thisisarow
    "); - - -// =[ 6 ]============================================================================== - - -equal(textile.convert( // The textile - - "|a|b|c|\n"+ - "| |2|3|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    abc
    23
    "); - - -// =[ 7 ]============================================================================== - - -equal(textile.convert( // The textile - - "table{width: 200px; border:2px solid gray;}.\n"+ - "|_=. Alignment|\n"+ - "|=. centered|\n"+ - "|=(. a bit right|\n"+ - "|=). a bit left|\n"+ - "|>). almost right|\n"+ - "|<(. almost left|\n"+ - "|>. right|\n"+ - "|<. left|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    Alignment
    centered
    a bit right
    a bit left
    almost right
    almost left
    right
    left
    "); - - -// =[ 8 ]============================================================================== - - -equal(textile.convert( // The textile - - "|{background:#ddd}. Cell with gray background|Normal cell|\n"+ - "|\\2. Cell spanning 2 columns|\n"+ - "|/2. Cell spanning 2 rows|one|\n"+ - "|two|\n"+ - "|>. Right-aligned cell|<. Left-aligned cell|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    Cell with gray backgroundNormal cell
    Cell spanning 2 columns
    Cell spanning 2 rowsone
    two
    Right-aligned cellLeft-aligned cell
    "); - - -// =[ 9 ]============================================================================== - - -equal(textile.convert( // The textile - - "|1|2|3|\n"+ - "|1|/3. 2|3|\n"+ - "|1|3|\n"+ - "|1|3|\n"+ - "|1|2|3|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    123
    123
    13
    13
    123
    " - -,"row spanning mid-row"); - - -// =[ 10 ]============================================================================== - - -equal(textile.convert( // The textile - - "{background:#ddd}. |S|Target|Complete|App|Milestone|\n"+ - "|!/i/g.gif!|11/29/04|11/29/04|011|XML spec complete (KH is on schedule)|\n"+ - "|!/i/g.gif!|11/22/04|11/22/04|070|Dialog pass 1 builds an index file|\n"+ - "|!/i/g.gif!|11/24/04|11/24/04|070|Dialog pass 2 98% complete|\n"+ - "|!/i/g.gif!|11/30/04|11/30/04|070|Feature complete. Passes end-to-end smoke test.|\n"+ - "|!/i/w.gif!|12/02/04| |011|Dialog pass 1 and 2 complete (98+%)|\n"+ - "|!/i/w.gif!|12/03/04| |081|Feature complete|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    STargetCompleteAppMilestone
    \"\"11/29/0411/29/04011XML spec complete (KH is on schedule)
    \"\"11/22/0411/22/04070Dialog pass 1 builds an index file
    \"\"11/24/0411/24/04070Dialog pass 2 98% complete
    \"\"11/30/0411/30/04070Feature complete. Passes end-to-end smoke test.
    \"\"12/02/04 011Dialog pass 1 and 2 complete (98+%)
    \"\"12/03/04 081Feature complete
    "); - - -// =[ 11 ]============================================================================== - - -equal(textile.convert( // The textile - - "table(my_class).\n"+ - "|_\\2. a |_. b |_. c |\n"+ - "| 1 | 2 | 3 | 4 |" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    a b c
    1 2 3 4
    " - -,"combined table header and colspan"); - - -// =[ 12 ]============================================================================== - - -equal(textile.convert( // The textile - - "|a|b|c|\n"+ - "\n"+ - "|1|2|3|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    abc
    \n"+ - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    123
    " - -,"two adjacent tables"); - - -// =[ 13 ]============================================================================== - - -equal(textile.convert( // The textile - - "|[en]. lang-ok|{color:red;}. style-ok|(myclass). class-ok|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    lang-okstyle-okclass-ok
    " - -,"with cell attributes"); - - -// =[ 14 ]============================================================================== - - -equal(textile.convert( // The textile - - "|[en]lang-bad|{color:red;}style-bad|(myclass)class-bad|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    [en]lang-bad{color:red;}style-bad(myclass)class-bad
    " - -,"with improper cell attributes"); - - -// =[ 15 ]============================================================================== - - -equal(textile.convert( // The textile - - "|a|b\n"+ - "b|\n"+ - "|c\n"+ - "c|d|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    ab
    \n"+ - "b
    c
    \n"+ - "c
    d
    " - -,"with line breaks in the cell"); - - -// =[ 16 ]============================================================================== - - -equal(textile.convert( // The textile - - "|a|b|\n"+ - "|a|\n"+ - "|a|b|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    ab
    a
    ab
    " - -,"with missing cells"); - - -// =[ 17 ]============================================================================== - - -equal(textile.convert( // The textile - - "||b|\n"+ - "|a||\n"+ - "|a| |" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    b
    a
    a
    " - -,"with empty cells"); - - -}); - diff --git a/test/converted/textism.js b/test/converted/textism.js deleted file mode 100644 index 8e23a72..0000000 --- a/test/converted/textism.js +++ /dev/null @@ -1,615 +0,0 @@ -test('textism.yml', function () { - - -// =[ 1 ]============================================================================== - - -equal(textile.convert( // The textile - - "h1. Header 1" - -), // Should output - - "

    Header 1

    " - -,"header one"); - - -// =[ 2 ]============================================================================== - - -equal(textile.convert( // The textile - - "h2. Header 2" - -), // Should output - - "

    Header 2

    " - -,"header two"); - - -// =[ 3 ]============================================================================== - - -equal(textile.convert( // The textile - - "h3. Header 3" - -), // Should output - - "

    Header 3

    " - -,"header three"); - - -// =[ 4 ]============================================================================== - - -equal(textile.convert( // The textile - - "h4. Header 4" - -), // Should output - - "

    Header 4

    " - -,"header four"); - - -// =[ 5 ]============================================================================== - - -equal(textile.convert( // The textile - - "h5. Header 5" - -), // Should output - - "
    Header 5
    " - -,"header five"); - - -// =[ 6 ]============================================================================== - - -equal(textile.convert( // The textile - - "h6. Header 6" - -), // Should output - - "
    Header 6
    " - -,"header six"); - - -// =[ 7 ]============================================================================== - - -equal(textile.convert( // The textile - - "Any old text.\n"+ - "\n"+ - "bq. A block quotation.\n"+ - "\n"+ - "Any old text.\n"+ - "" - -), // Should output - - "

    Any old text.

    \n"+ - "
    \n"+ - "

    A block quotation.

    \n"+ - "
    \n"+ - "

    Any old text.

    " - -,"blockquote"); - - -// =[ 8 ]============================================================================== - - -equal(textile.convert( // The textile - - "# A first item\n"+ - "# A second item\n"+ - "# A third item\n"+ - "# A fourth item" - -), // Should output - - "
      \n"+ - "\t
    1. A first item
    2. \n"+ - "\t
    3. A second item
    4. \n"+ - "\t
    5. A third item
    6. \n"+ - "\t
    7. A fourth item
    8. \n"+ - "
    "); - - -// =[ 9 ]============================================================================== - - -equal(textile.convert( // The textile - - "* A first item\n"+ - "* A second item\n"+ - "* A third item\n"+ - "* A fourth item\n"+ - "" - -), // Should output - - "
      \n"+ - "\t
    • A first item
    • \n"+ - "\t
    • A second item
    • \n"+ - "\t
    • A third item
    • \n"+ - "\t
    • A fourth item
    • \n"+ - "
    "); - - -// =[ 10 ]============================================================================== - - -equal(textile.convert( // The textile - - "_a phrase_" - -), // Should output - - "

    a phrase

    "); - - -// =[ 11 ]============================================================================== - - -equal(textile.convert( // The textile - - "__a phrase__" - -), // Should output - - "

    a phrase

    "); - - -// =[ 12 ]============================================================================== - - -equal(textile.convert( // The textile - - "*a phrase*" - -), // Should output - - "

    a phrase

    "); - - -// =[ 13 ]============================================================================== - - -equal(textile.convert( // The textile - - "**a phrase**" - -), // Should output - - "

    a phrase

    "); - - -// =[ 14 ]============================================================================== - - -equal(textile.convert( // The textile - - "Nabokov's ??Pnin??" - -), // Should output - - "

    Nabokov’s Pnin

    "); - - -// =[ 15 ]============================================================================== - - -equal(textile.convert( // The textile - - "A very [-extra-]ordinary day." - -), // Should output - - "

    A very extraordinary day.

    " - -,"del part of word"); - - -// =[ 16 ]============================================================================== - - -equal(textile.convert( // The textile - - "An [-extra-extra-]ordinary day." - -), // Should output - - "

    An extra-extraordinary day.

    " - -,"del part of word that contains a hyphen"); - - -// =[ 17 ]============================================================================== - - -equal(textile.convert( // The textile - - "Delete -a phrase- this way." - -), // Should output - - "

    Delete a phrase this way.

    " - -,"del a phrase"); - - -// =[ 18 ]============================================================================== - - -equal(textile.convert( // The textile - - "Delete -a no-nonsense phrase- this way." - -), // Should output - - "

    Delete a no-nonsense phrase this way.

    " - -,"del a phrase that contains hyphens"); - - -// =[ 19 ]============================================================================== - - -equal(textile.convert( // The textile - - "+a phrase+" - -), // Should output - - "

    a phrase

    "); - - -// =[ 20 ]============================================================================== - - -equal(textile.convert( // The textile - - "^a phrase^" - -), // Should output - - "

    a phrase

    "); - - -// =[ 21 ]============================================================================== - - -equal(textile.convert( // The textile - - "~a phrase~" - -), // Should output - - "

    a phrase

    "); - - -// =[ 22 ]============================================================================== - - -equal(textile.convert( // The textile - - "%(myclass)SPAN%" - -), // Should output - - "

    SPAN

    "); - - -// =[ 23 ]============================================================================== - - -equal(textile.convert( // The textile - - "%{color:red}red%" - -), // Should output - - "

    red

    "); - - -// =[ 24 ]============================================================================== - - -equal(textile.convert( // The textile - - "%[fr]rouge%" - -), // Should output - - "

    rouge

    "); - - -// =[ 25 ]============================================================================== - - -equal(textile.convert( // The textile - - "_(big)red_" - -), // Should output - - "

    red

    "); - - -// =[ 26 ]============================================================================== - - -equal(textile.convert( // The textile - - "p=. A centered paragraph." - -), // Should output - - "

    A centered paragraph.

    "); - - -// =[ 27 ]============================================================================== - - -equal(textile.convert( // The textile - - "p(bob). A paragraph" - -), // Should output - - "

    A paragraph

    "); - - -// =[ 28 ]============================================================================== - - -equal(textile.convert( // The textile - - "p{color:#ddd}. A paragraph" - -), // Should output - - "

    A paragraph

    "); - - -// =[ 29 ]============================================================================== - - -equal(textile.convert( // The textile - - "p[fr]. A paragraph" - -), // Should output - - "

    A paragraph

    "); - - -// =[ 30 ]============================================================================== - - -equal(textile.convert( // The textile - - "h2()>. right-aligned header2, indented 1em both side" - -), // Should output - - "

    right-aligned header2, indented 1em both side

    "); - - -// =[ 31 ]============================================================================== - - -equal(textile.convert( // The textile - - "h3=. centered header" - -), // Should output - - "

    centered header

    "); - - -// =[ 32 ]============================================================================== - - -equal(textile.convert( // The textile - - "!>/image.gif! right-aligned image" - -), // Should output - - "

    \"\" right-aligned image

    "); - - -// =[ 33 ]============================================================================== - - -equal(textile.convert( // The textile - - "p[no]{color:red}. A Norse of a different colour." - -), // Should output - - "

    A Norse of a different colour.

    "); - - -// =[ 34 ]============================================================================== - - -equal(textile.convert( // The textile - - "|This|is|a|simple|table|\n"+ - "|This|is|a|simple|row|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    Thisisasimpletable
    Thisisasimplerow
    "); - - -// =[ 35 ]============================================================================== - - -equal(textile.convert( // The textile - - "table{border:1px solid black}.\n"+ - "|This|is|a|row|\n"+ - "|This|is|a|row|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    Thisisarow
    Thisisarow
    "); - - -// =[ 36 ]============================================================================== - - -equal(textile.convert( // The textile - - "{background:#ddd}. |This|is|a|row|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    Thisisarow
    "); - - -// =[ 37 ]============================================================================== - - -equal(textile.convert( // The textile - - "|{background:#ddd}. Cell with gray background|\n"+ - "|\\2. Cell spanning 2 columns|\n"+ - "|/3. Cell spanning 3 rows|\n"+ - "|>. Right-aligned cell|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    Cell with gray background
    Cell spanning 2 columns
    Cell spanning 3 rows
    Right-aligned cell
    "); - - -// =[ 38 ]============================================================================== - - -equal(textile.convert( // The textile - - "h2{color:green}. This is a title\n"+ - "\n"+ - "h3. This is a subhead\n"+ - "\n"+ - "p{color:red}. This is some text of dubious character. Isn't the use of \"quotes\" just lazy writing -- and theft of 'intellectual property' besides? I think the time has come to see a block quote.\n"+ - "\n"+ - "bq[fr]. This is a block quote. I'll admit it's not the most exciting block quote ever devised.\n"+ - "\n"+ - "Simple list:\n"+ - "\n"+ - "# one\n"+ - "# two\n"+ - "# three\n"+ - "\n"+ - "Multi-level list:\n"+ - "\n"+ - "# one\n"+ - "## aye\n"+ - "## bee\n"+ - "## see\n"+ - "# two\n"+ - "## x\n"+ - "## y\n"+ - "# three\n"+ - "" - -), // Should output - - "

    This is a title

    \n"+ - "

    This is a subhead

    \n"+ - "

    This is some text of dubious character. Isn’t the use of “quotes” just lazy writing — and theft of ‘intellectual property’ besides? I think the time has come to see a block quote.

    \n"+ - "
    \n"+ - "

    This is a block quote. I’ll admit it’s not the most exciting block quote ever devised.

    \n"+ - "
    \n"+ - "

    Simple list:

    \n"+ - "
      \n"+ - "\t
    1. one
    2. \n"+ - "\t
    3. two
    4. \n"+ - "\t
    5. three
    6. \n"+ - "
    \n"+ - "

    Multi-level list:

    \n"+ - "
      \n"+ - "\t
    1. one\n"+ - "\t
        \n"+ - "\t\t
      1. aye
      2. \n"+ - "\t\t
      3. bee
      4. \n"+ - "\t\t
      5. see
      6. \n"+ - "\t
    2. \n"+ - "\t
    3. two\n"+ - "\t
        \n"+ - "\t\t
      1. x
      2. \n"+ - "\t\t
      3. y
      4. \n"+ - "\t
    4. \n"+ - "\t
    5. three
    6. \n"+ - "
    " - -,"basics"); - - -}); - diff --git a/test/converted/threshold.js b/test/converted/threshold.js deleted file mode 100644 index 1aa93f6..0000000 --- a/test/converted/threshold.js +++ /dev/null @@ -1,1563 +0,0 @@ -test('threshold.yml', function () { - - -// =[ 1 ]============================================================================== - - -equal(textile.convert( // The textile - - "A paragraph.\n"+ - "\n"+ - "Another paragraph." - -), // Should output - - "

    A paragraph.

    \n"+ - "

    Another paragraph.

    " - -,"paragraph"); - - -// =[ 2 ]============================================================================== - - -equal(textile.convert( // The textile - - "A paragraph with\n"+ - "a line break." - -), // Should output - - "

    A paragraph with
    \n"+ - "a line break.

    " - -,"line breaks"); - - -// =[ 3 ]============================================================================== - - -equal(textile.convert( // The textile - - "Here's some bold text." - -), // Should output - - "

    Here’s some bold text.

    " - -,"xhtml tags"); - - -// =[ 4 ]============================================================================== - - -equal(textile.convert( // The textile - - " No paragraph tags here." - -), // Should output - - "No paragraph tags here." - -,"no paragraph tags"); - - -// =[ 5 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"Proceed!\" said he to the host." - -), // Should output - - "

    “Proceed!” said he to the host.

    " - -,"smart quotes"); - - -// =[ 6 ]============================================================================== - - -equal(textile.convert( // The textile - - "'Proceed!' said he to the host." - -), // Should output - - "

    ‘Proceed!’ said he to the host.

    " - -,"smart quotes 2"); - - -// =[ 7 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"'I swear, captain,' replied I.\"" - -), // Should output - - "

    “‘I swear, captain,’ replied I.”

    " - -,"nested quotation marks"); - - -// =[ 8 ]============================================================================== - - -equal(textile.convert( // The textile - - "'\"I swear, captain,\" replied I.'" - -), // Should output - - "

    ‘“I swear, captain,” replied I.’

    " - -,"nested quotation marks 2"); - - -// =[ 9 ]============================================================================== - - -equal(textile.convert( // The textile - - "Greengrocers' apostrophe's." - -), // Should output - - "

    Greengrocers’ apostrophe’s.

    " - -,"apostrophe glyphs"); - - -// =[ 10 ]============================================================================== - - -equal(textile.convert( // The textile - - "You know the Italian proverb -- Chi ha compagno ha padrone." - -), // Should output - - "

    You know the Italian proverb — Chi ha compagno ha padrone.

    " - -,"em-dash glyphs"); - - -// =[ 11 ]============================================================================== - - -equal(textile.convert( // The textile - - "You know the Italian proverb--Chi ha compagno ha padrone." - -), // Should output - - "

    You know the Italian proverb—Chi ha compagno ha padrone.

    " - -,"em-dash glyphs 2"); - - -// =[ 12 ]============================================================================== - - -equal(textile.convert( // The textile - - "You know the Italian proverb - Chi ha compagno ha padrone." - -), // Should output - - "

    You know the Italian proverb – Chi ha compagno ha padrone.

    " - -,"en-dash glyphs"); - - -// =[ 13 ]============================================================================== - - -equal(textile.convert( // The textile - - "Meanwhile..." - -), // Should output - - "

    Meanwhile…

    " - -,"ellipsis character"); - - -// =[ 14 ]============================================================================== - - -equal(textile.convert( // The textile - - "1 x 2 x 3 = 6" - -), // Should output - - "

    1 × 2 × 3 = 6

    " - -,"dimension character"); - - -// =[ 15 ]============================================================================== - - -equal(textile.convert( // The textile - - "1x2x3 = 6" - -), // Should output - - "

    1×2×3 = 6

    " - -,"dimension character 2"); - - -// =[ 16 ]============================================================================== - - -equal(textile.convert( // The textile - - "Registered(r) Trademark(tm) Copyright (c)." - -), // Should output - - "

    Registered® Trademark™ Copyright ©.

    " - -,"trademark register copyright"); - - -// =[ 17 ]============================================================================== - - -equal(textile.convert( // The textile - - "ABC(Always Be Closing)" - -), // Should output - - "

    ABC

    " - -,"acronyms"); - - -// =[ 18 ]============================================================================== - - -equal(textile.convert( // The textile - - "IBM or HAL" - -), // Should output - - "

    IBM or HAL

    " - -,"uppercase"); - - -// =[ 19 ]============================================================================== - - -equal(textile.convert( // The textile - - "The _underlying_ cause." - -), // Should output - - "

    The underlying cause.

    " - -,"emphasis"); - - -// =[ 20 ]============================================================================== - - -equal(textile.convert( // The textile - - "The *underlying* cause." - -), // Should output - - "

    The underlying cause.

    " - -,"strong text"); - - -// =[ 21 ]============================================================================== - - -equal(textile.convert( // The textile - - "The __underlying__ cause." - -), // Should output - - "

    The underlying cause.

    " - -,"italic text"); - - -// =[ 22 ]============================================================================== - - -equal(textile.convert( // The textile - - "The **underlying** cause." - -), // Should output - - "

    The underlying cause.

    " - -,"bold text"); - - -// =[ 23 ]============================================================================== - - -equal(textile.convert( // The textile - - "??The Count of Monte Cristo??, by Dumas." - -), // Should output - - "

    The Count of Monte Cristo, by Dumas.

    " - -,"citation"); - - -// =[ 24 ]============================================================================== - - -equal(textile.convert( // The textile - - "Scratch -that-, replace with +this+." - -), // Should output - - "

    Scratch that, replace with this.

    " - -,"inserted and deleted text"); - - -// =[ 25 ]============================================================================== - - -equal(textile.convert( // The textile - - "log ~2~ n" - -), // Should output - - "

    log 2 n

    " - -,"subscript"); - - -// =[ 26 ]============================================================================== - - -equal(textile.convert( // The textile - - "2 ^x^" - -), // Should output - - "

    2 x

    " - -,"superscript"); - - -// =[ 27 ]============================================================================== - - -equal(textile.convert( // The textile - - "The %underlying% cause." - -), // Should output - - "

    The underlying cause.

    " - -,"span tag"); - - -// =[ 28 ]============================================================================== - - -equal(textile.convert( // The textile - - "About the @
    @ tag." - -), // Should output - - "

    About the <hr /> tag.

    " - -,"code"); - - -// =[ 29 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":http://example.com/" - -), // Should output - - "

    link text

    " - -,"links"); - - -// =[ 30 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text\":/example" - -), // Should output - - "

    link text

    " - -,"local links"); - - -// =[ 31 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"link text(with title)\":http://example.com/" - -), // Should output - - "

    link text

    " - -,"link title"); - - -// =[ 32 ]============================================================================== - - -equal(textile.convert( // The textile - - "Here's \"a link\":tstate, and\n"+ - "\"another link\":tstate to the same site.\n"+ - "\n"+ - "[tstate]http://thresholdstate.com/" - -), // Should output - - "

    Here’s a link, and
    \n"+ - "another link to the same site.

    " - -,"link alias"); - - -// =[ 33 ]============================================================================== - - -equal(textile.convert( // The textile - - "!/img.gif!" - -), // Should output - - "

    \"\"

    " - -,"image"); - - -// =[ 34 ]============================================================================== - - -equal(textile.convert( // The textile - - "!http://thresholdstate.com/img.gif!" - -), // Should output - - "

    \"\"

    " - -,"image 2"); - - -// =[ 35 ]============================================================================== - - -equal(textile.convert( // The textile - - "!/img.gif(alt text)!" - -), // Should output - - "

    \"alt

    " - -,"image alt"); - - -// =[ 36 ]============================================================================== - - -equal(textile.convert( // The textile - - "!/img.gif!:http://textpattern.com/" - -), // Should output - - "

    \"\"

    " - -,"image links"); - - -// =[ 37 ]============================================================================== - - -equal(textile.convert( // The textile - - "h1. Heading 1" - -), // Should output - - "

    Heading 1

    " - -,"headers"); - - -// =[ 38 ]============================================================================== - - -equal(textile.convert( // The textile - - "h2. Heading 2" - -), // Should output - - "

    Heading 2

    " - -,"headers 2"); - - -// =[ 39 ]============================================================================== - - -equal(textile.convert( // The textile - - "h6. Heading 6" - -), // Should output - - "
    Heading 6
    " - -,"headers 3"); - - -// =[ 40 ]============================================================================== - - -equal(textile.convert( // The textile - - "p. A paragraph.\n"+ - "Continued.\n"+ - "\n"+ - "Also a paragraph." - -), // Should output - - "

    A paragraph.
    \n"+ - "Continued.

    \n"+ - "

    Also a paragraph.

    " - -,"paragraph text"); - - -// =[ 41 ]============================================================================== - - -equal(textile.convert( // The textile - - "bq. A quotation.\n"+ - "Continued.\n"+ - "\n"+ - "Regular paragraph." - -), // Should output - - "
    \n"+ - "

    A quotation.
    \n"+ - "Continued.

    \n"+ - "
    \n"+ - "

    Regular paragraph.

    " - -,"block quote"); - - -// =[ 42 ]============================================================================== - - -equal(textile.convert( // The textile - - "bq.:http://thresholdstate.com/ A cited quotation." - -), // Should output - - "
    \n"+ - "

    A cited quotation.

    \n"+ - "
    " - -,"block quote citation"); - - -// =[ 43 ]============================================================================== - - -equal(textile.convert( // The textile - - "A footnote reference[1].\n"+ - "\n"+ - "fn1. The footnote." - -), // Should output - - "

    A footnote reference1.

    \n"+ - "

    1 The footnote.

    " - -,"footnotes"); - - -// =[ 44 ]============================================================================== - - -equal(textile.convert( // The textile - - "bc. " - -), // Should output - - "
    <script>\n"+
    -  "// a Javascript example\n"+
    -  "alert(\"Hello World\");\n"+
    -  "</script>
    " - -,"block code"); - - -// =[ 45 ]============================================================================== - - -equal(textile.convert( // The textile - - "pre. Pre-formatted\n"+ - "text" - -), // Should output - - "
    Pre-formatted\n"+
    -  "text
    " - -,"preformatted text"); - - -// =[ 46 ]============================================================================== - - -equal(textile.convert( // The textile - - "notextile. \n"+ - "" - -), // Should output - - "\n"+ - "" - -,"notextile"); - - -// =[ 47 ]============================================================================== - - -equal(textile.convert( // The textile - - "p(myclass). My classy paragraph." - -), // Should output - - "

    My classy paragraph.

    " - -,"class attribute"); - - -// =[ 48 ]============================================================================== - - -equal(textile.convert( // The textile - - "p(#myid). My ID paragraph." - -), // Should output - - "

    My ID paragraph.

    " - -,"id attribute"); - - -// =[ 49 ]============================================================================== - - -equal(textile.convert( // The textile - - "p{color:red}. Red rum." - -), // Should output - - "

    Red rum.

    " - -,"style attribute"); - - -// =[ 50 ]============================================================================== - - -equal(textile.convert( // The textile - - "p[fr-fr]. En français." - -), // Should output - - "

    En français.

    " - -,"lang attribute"); - - -// =[ 51 ]============================================================================== - - -equal(textile.convert( // The textile - - "A *(myclass)classy* phrase." - -), // Should output - - "

    A classy phrase.

    " - -,"phrase modifiers"); - - -// =[ 52 ]============================================================================== - - -equal(textile.convert( // The textile - - "An _(#myid2)ID_ phrase." - -), // Should output - - "

    An ID phrase.

    " - -,"phrase modifiers 2"); - - -// =[ 53 ]============================================================================== - - -equal(textile.convert( // The textile - - "The %{color:blue}blue% room." - -), // Should output - - "

    The blue room.

    " - -,"phrase modifiers 3"); - - -// =[ 54 ]============================================================================== - - -equal(textile.convert( // The textile - - "p(myclass#myid3){color:green}[de-de]. A complex paragraph." - -), // Should output - - "

    A complex paragraph.

    " - -,"block and phrase attributes combined"); - - -// =[ 55 ]============================================================================== - - -equal(textile.convert( // The textile - - "A ??(myclass#myid4){color:green}[de-de]complex?? phrase." - -), // Should output - - "

    A complex phrase.

    " - -,"block and phrase attributes combined 2"); - - -// =[ 56 ]============================================================================== - - -equal(textile.convert( // The textile - - "bq.. A quote.\n"+ - "\n"+ - "The quote continued.\n"+ - "\n"+ - "p. Back to paragraph text." - -), // Should output - - "
    \n"+ - "

    A quote.

    \n"+ - "

    The quote continued.

    \n"+ - "
    \n"+ - "

    Back to paragraph text.

    " - -,"extended blocks"); - - -// =[ 57 ]============================================================================== - - -equal(textile.convert( // The textile - - "A PHP code example.\n"+ - "\n"+ - "bc.. \n"+ - "\n"+ - "p. Following paragraph." - -), // Should output - - "

    A PHP code example.

    \n"+ - "
    <?php\n"+
    -  "function hello() {\n"+
    -  "// display a hello message\n"+
    -  "\n"+
    -  "print \"Hello, World\";\n"+
    -  "}\n"+
    -  "?>
    \n"+ - "

    Following paragraph.

    " - -,"extended block code"); - - -// =[ 58 ]============================================================================== - - -equal(textile.convert( // The textile - - "p(myclass).. A classy paragraph.\n"+ - "\n"+ - "Another classy paragraph.\n"+ - "\n"+ - "p. Not so classy." - -), // Should output - - "

    A classy paragraph.

    \n"+ - "

    Another classy paragraph.

    \n"+ - "

    Not so classy.

    " - -,"extended block attributes"); - - -// =[ 59 ]============================================================================== - - -equal(textile.convert( // The textile - - "bq(myclass).. Quote paragraph 1.\n"+ - "\n"+ - "Paragraph 2." - -), // Should output - - "
    \n"+ - "

    Quote paragraph 1.

    \n"+ - "

    Paragraph 2.

    \n"+ - "
    " - -,"extended block quote attributes"); - - -// =[ 60 ]============================================================================== - - -equal(textile.convert( // The textile - - "bc(myclass).. Code block 1.\n"+ - "\n"+ - "Code block 2." - -), // Should output - - "
    Code block 1.\n"+
    -  "\n"+
    -  "Code block 2.
    " - -,"extended block code attributes"); - - -// =[ 61 ]============================================================================== - - -equal(textile.convert( // The textile - - "bold and italic, the hard way." - -), // Should output - - "

    bold and italic, the hard way.

    " - -,"raw xhtml left in tact"); - - -// =[ 62 ]============================================================================== - - -equal(textile.convert( // The textile - - "
    My div
    " - -), // Should output - - "
    My div
    " - -,"paragraphs entirely raw xhtml"); - - -// =[ 63 ]============================================================================== - - -equal(textile.convert( // The textile - - "\"image\"" - -), // Should output - - "

    \"image\"

    " - -,"paragraphs with inline xhtml"); - - -// =[ 64 ]============================================================================== - - -equal(textile.convert( // The textile - - "I'll make my own way." - -), // Should output - - "

    I’ll make my own way.

    " - -,"paragraphs with inline xhtml 2"); - - -// =[ 65 ]============================================================================== - - -equal(textile.convert( // The textile - - "
    inside
    and outside." - -), // Should output - - "
    inside
    \n

    and outside.

    " - -,"paragraphs partly enclosed in xhtml block tags"); - - -// =[ 66 ]============================================================================== - - -equal(textile.convert( // The textile - - "
    \n"+ - " My div\n"+ - "
    " - -), // Should output - - "
    \n"+ - "My div\n"+ - "
    " - -,"complex xhtml blocks"); - - -// =[ 67 ]============================================================================== - - -equal(textile.convert( // The textile - - "notextile..
    \n"+ - "\n"+ - "My div\n"+ - "\n"+ - "
    " - -), // Should output - - "
    \n"+ - "\n"+ - "My div\n"+ - "\n"+ - "
    " - -,"complex xhtml blocks 2"); - - -// =[ 68 ]============================================================================== - - -equal(textile.convert( // The textile - - "
    \n"+ - " My *div*\n"+ - "
    " - -), // Should output - - "
    \n"+ - "My div\n"+ - "
    " - -,"complex xhtml blocks with inline formatting"); - - -// =[ 69 ]============================================================================== - - -equal(textile.convert( // The textile - - "
    \n"+
    -  "A HTML example\n"+
    -  "
    " - -), // Should output - - "
    \n"+
    -  "A HTML <b>example</b>\n"+
    -  "
    " - -,"explicit pre escapement"); - - -// =[ 70 ]============================================================================== - - -equal(textile.convert( // The textile - - "\n"+ - "Another HTML example\n"+ - "" - -), // Should output - - "

    \n"+ - "Another HTML <b>example</b>\n"+ - "

    " - -,"explicit code escapement"); - - -// =[ 71 ]============================================================================== - - -equal(textile.convert( // The textile - - "\n"+ - "p. Leave me alone\n"+ - "" - -), // Should output - - "p. Leave me alone" - -,"notextile tags"); - - -// =[ 72 ]============================================================================== - - -equal(textile.convert( // The textile - - "p<. Left-aligned paragraph." - -), // Should output - - "

    Left-aligned paragraph.

    " - -,"left aligned text"); - - -// =[ 73 ]============================================================================== - - -equal(textile.convert( // The textile - - "h3>. Right-aligned heading." - -), // Should output - - "

    Right-aligned heading.

    " - -,"right aligned text"); - - -// =[ 74 ]============================================================================== - - -equal(textile.convert( // The textile - - "p<>. Justified paragraph." - -), // Should output - - "

    Justified paragraph.

    " - -,"justified text"); - - -// =[ 75 ]============================================================================== - - -equal(textile.convert( // The textile - - "h3=. Centered heading." - -), // Should output - - "

    Centered heading.

    " - -,"centered text"); - - -// =[ 76 ]============================================================================== - - -equal(textile.convert( // The textile - - "p(. Left pad 1em." - -), // Should output - - "

    Left pad 1em.

    " - -,"padding"); - - -// =[ 77 ]============================================================================== - - -equal(textile.convert( // The textile - - "p)). Right pad 2em." - -), // Should output - - "

    Right pad 2em.

    " - -,"padding 2"); - - -// =[ 78 ]============================================================================== - - -equal(textile.convert( // The textile - - "p(). Left and right pad 1em." - -), // Should output - - "

    Left and right pad 1em.

    " - -,"padding 3"); - - -// =[ 79 ]============================================================================== - - -equal(textile.convert( // The textile - - "# Item one\n"+ - "# Item two\n"+ - "# Item three" - -), // Should output - - "
      \n"+ - "\t
    1. Item one
    2. \n"+ - "\t
    3. Item two
    4. \n"+ - "\t
    5. Item three
    6. \n"+ - "
    " - -,"numeric lists"); - - -// =[ 80 ]============================================================================== - - -equal(textile.convert( // The textile - - "* Item A\n"+ - "* Item B\n"+ - "* Item C" - -), // Should output - - "
      \n"+ - "\t
    • Item A
    • \n"+ - "\t
    • Item B
    • \n"+ - "\t
    • Item C
    • \n"+ - "
    " - -,"bulleted lists"); - - -// =[ 81 ]============================================================================== - - -equal(textile.convert( // The textile - - "# Item one\n"+ - "## Item one-A\n"+ - "## Item one-B\n"+ - "### Item one-B-a\n"+ - "# Item two" - -), // Should output - - "
      \n"+ - "\t
    1. Item one\n"+ - "\t
        \n"+ - "\t\t
      1. Item one-A
      2. \n"+ - "\t\t
      3. Item one-B\n"+ - "\t\t
          \n"+ - "\t\t\t
        1. Item one-B-a
        2. \n"+ - "\t\t
      4. \n"+ - "\t
    2. \n"+ - "\t
    3. Item two
    4. \n"+ - "
    " - -,"nested lists"); - - -// =[ 82 ]============================================================================== - - -equal(textile.convert( // The textile - - "|a|simple|table|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    asimpletable
    " - -,"tables"); - - -// =[ 83 ]============================================================================== - - -equal(textile.convert( // The textile - - "|_. a|_. table|_. heading|\n"+ - "|a|table|row|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    atableheading
    atablerow
    " - -,"table heading cells"); - - -// =[ 84 ]============================================================================== - - -equal(textile.convert( // The textile - - "|a|{color:red}. styled|cell|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    astyledcell
    " - -,"cell attributes"); - - -// =[ 85 ]============================================================================== - - -equal(textile.convert( // The textile - - "(rowclass). |a|classy|row|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    aclassyrow
    " - -,"row attributes"); - - -// =[ 86 ]============================================================================== - - -equal(textile.convert( // The textile - - "table(tableclass).\n"+ - "|a|classy|table|\n"+ - "|a|classy|table|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    aclassytable
    aclassytable
    " - -,"table attributes"); - - -// =[ 87 ]============================================================================== - - -equal(textile.convert( // The textile - - "|^. top alignment|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    top alignment
    " - -,"vertical alignment"); - - -// =[ 88 ]============================================================================== - - -equal(textile.convert( // The textile - - "|-. middle alignment|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    middle alignment
    " - -,"vertical alignment 2"); - - -// =[ 89 ]============================================================================== - - -equal(textile.convert( // The textile - - "|~. bottom alignment|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    bottom alignment
    " - -,"vertical alignment 3"); - - -// =[ 90 ]============================================================================== - - -equal(textile.convert( // The textile - - "|\\2. spans two cols |\n"+ - "| col 1 | col 2 |" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    spans two cols
    col 1 col 2
    " - -,"column span"); - - -// =[ 91 ]============================================================================== - - -equal(textile.convert( // The textile - - "|/3. spans 3 rows | row a |\n"+ - "| row b |\n"+ - "| row c |" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
    spans 3 rows row a
    row b
    row c
    " - -,"row span"); - - -// =[ 92 ]============================================================================== - - -equal(textile.convert( // The textile - - "this*won't*work" - -), // Should output - - "

    this*won’t*work

    " - -,"whitespace required"); - - -// =[ 93 ]============================================================================== - - -equal(textile.convert( // The textile - - "this[*will*]work" - -), // Should output - - "

    thiswillwork

    " - -,"modifier without whitespace"); - - -// =[ 94 ]============================================================================== - - -equal(textile.convert( // The textile - - "1[^st^], 2[^nd^], 3[^rd^]." - -), // Should output - - "

    1st, 2nd, 3rd.

    " - -,"modifier without whitespace 2"); - - -// =[ 95 ]============================================================================== - - -equal(textile.convert( // The textile - - "2 log[~n~]" - -), // Should output - - "

    2 logn

    " - -,"modifier without whitespace 3"); - - -// =[ 96 ]============================================================================== - - -equal(textile.convert( // The textile - - "A close[!/img.gif!]image.\n"+ - "A tight[\"text\":http://thresholdstate.com/]link.\n"+ - "A [\"footnoted link\":http://thresholdstate.com/][1]." - -), // Should output - - "

    A close\"\"image.
    \n"+ - "A tighttextlink.
    \n"+ - "A footnoted link1.

    " - -,"modifier without whitespace 4"); - - -}); - diff --git a/test/definitions.js b/test/definitions.js new file mode 100644 index 0000000..681e8ee --- /dev/null +++ b/test/definitions.js @@ -0,0 +1,85 @@ +// definitions.yml +import test from 'ava'; +import textile from '../src'; + +test( 'redcloth definition list', function ( t ) { + let tx = "here is a RedCloth definition list:\n\n\ +- yes := no\n\ +- no:=no\n\ +- maybe:= yes"; + t.is( textile.convert( tx ), + "

    here is a RedCloth definition list:

    \n\ +
    \n\ +\t
    yes
    \n\ +\t
    no
    \n\ +\t
    no
    \n\ +\t
    no
    \n\ +\t
    maybe
    \n\ +\t
    yes
    \n\ +
    ", tx ); +}); + + +test( 'with line breaks', function ( t ) { + let tx = "- term := you can have line breaks\n\ +just like other lists\n\ +- line-spanning\n\ +term := hey, slick!"; + t.is( textile.convert( tx ), + "
    \n\ +\t
    term
    \n\ +\t
    you can have line breaks
    \n\ +just like other lists
    \n\ +\t
    line-spanning
    \n\ +term
    \n\ +\t
    hey, slick!
    \n\ +
    ", tx ); +}); + + +test( 'double terms', function ( t ) { + let tx = "You can have multiple terms before a definition:\n\n\ +- textile\n\ +- fabric\n\ +- cloth := woven threads"; + t.is( textile.convert( tx ), + "

    You can have multiple terms before a definition:

    \n\ +
    \n\ +\t
    textile
    \n\ +\t
    fabric
    \n\ +\t
    cloth
    \n\ +\t
    woven threads
    \n\ +
    ", tx ); +}); + + +test( 'not a definition list', function ( t ) { + let tx = "- textile\n\ +- fabric\n\ +- cloth"; + t.is( textile.convert( tx ), + "

    - textile
    \n\ +- fabric
    \n\ +- cloth

    ", tx ); +}); + + +test( 'long definition list', function ( t ) { + let tx = "here is a long definition\n\n\ +- some term := \n\ +*sweet*\n\n\ +yes\n\n\ +ok =:\n\ +- regular term := no"; + t.is( textile.convert( tx ), + "

    here is a long definition

    \n\ +
    \n\ +\t
    some term
    \n\ +\t

    sweet

    \n\ +

    yes

    \n\ +

    ok

    \n\ +\t
    regular term
    \n\ +\t
    no
    \n\ +
    ", tx ); +}); + diff --git a/test/extra_whitespace.js b/test/extra_whitespace.js new file mode 100644 index 0000000..21faa27 --- /dev/null +++ b/test/extra_whitespace.js @@ -0,0 +1,39 @@ +// extra_whitespace.yml +import test from 'ava'; +import textile from '../src'; + +test( 'header with 1 blank line below', function ( t ) { + let tx = "h1. Header\n\n\ +text"; + t.is( textile.convert( tx ), + "

    Header

    \n\ +

    text

    ", tx ); +}); + + +test( 'header with 2 blank lines below', function ( t ) { + let tx = "h1. Header\n\n\n\ +text"; + t.is( textile.convert( tx ), + "

    Header

    \n\ +

    text

    ", tx ); +}); + + +test( 'header with 1 blank line above', function ( t ) { + let tx = "text\n\n\ +h1. Header"; + t.is( textile.convert( tx ), + "

    text

    \n\ +

    Header

    ", tx ); +}); + + +test( 'header with 2 blank lines above', function ( t ) { + let tx = "text\n\n\n\ +h1. Header"; + t.is( textile.convert( tx ), + "

    text

    \n\ +

    Header

    ", tx ); +}); + diff --git a/test/filter_pba.js b/test/filter_pba.js new file mode 100644 index 0000000..c65e77f --- /dev/null +++ b/test/filter_pba.js @@ -0,0 +1,17 @@ +// filter_pba.yml +import test from 'ava'; +import textile from '../src'; + +test( 'correct application of double quote entity when using styles', function ( t ) { + let tx = "p{background: #white url(\"../chunky_bacon.jpg\")}. The quick brown \"cartoon\" fox jumps over the lazy dog"; + t.is( textile.convert( tx ), + "

    The quick brown “cartoon” fox jumps over the lazy dog

    ", tx ); +}); + + +test( 'correct application of single quote entity when using styles', function ( t ) { + let tx = "p{background: #white url('../chunky_bacon.jpg')}. The quick brown 'cartoon' fox jumps over the lazy dog"; + t.is( textile.convert( tx ), + "

    The quick brown ‘cartoon’ fox jumps over the lazy dog

    ", tx ); +}); + diff --git a/test/html.js b/test/html.js new file mode 100644 index 0000000..2fe4789 --- /dev/null +++ b/test/html.js @@ -0,0 +1,370 @@ +// html.yml +import test from 'ava'; +import textile from '../src'; + +test( 'html:1', function ( t ) { + let tx = "*this is strong*"; + t.is( textile.convert( tx ), + "

    this is strong

    ", tx ); +}); + + +test( 'html:2', function ( t ) { + let tx = "*this test is strong*"; + t.is( textile.convert( tx ), + "

    this test is strong

    ", tx ); +}); + + +test( 'html:3', function ( t ) { + let tx = "A simple "; + t.is( textile.convert( tx ), + "

    A simple

    ", tx ); +}); + + +test( 'html:4', function ( t ) { + let tx = "A simple "; + t.is( textile.convert( tx ), + "

    A simple

    ", tx ); +}); + +// Does not confirm with PHP standard. +/* +test( 'no breaks between HTML elements', function ( t ) { + let tx = "
      \n\ +\t
    • You can put HTML code right in Textile.
    • \n\ +\t
    • It will not insert a break between elements
    • \n\ +\t
    • or wrap it all in a p tag.
    • \n\ +\t
    • It should insert a hard break\n\ +if you break.
    • \n\ +
    "; + t.is( textile.convert( tx ), + "
      \n\ +\t
    • You can put HTML code right in Textile.
    • \n\ +\t
    • It will not insert a break between elements
    • \n\ +\t
    • or wrap it all in a p tag.
    • \n\ +\t
    • It should insert a hard break
      \n\ +if you break.
    • \n\ +
    ", tx ); +}); +*/ + +test( 'line breaks', function ( t ) { + let tx = "I spoke.
    \n\ +And none replied."; + t.is( textile.convert( tx ), + "

    I spoke.
    \n\ +And none replied.

    ", tx ); +}); + + +test( 'mixing of textile and XHTML', function ( t ) { + let tx = "\"test\"\n\n\ +Regular *paragraph*.\n\n\ +
    \n\ +This is one paragraph.\n\n\ +This is another.\n\n\ +!an/image.jpg!\n\n\ +* A list\n\ +* in a div.\n\n\ +
    \n\n\ +Another paragraph."; + t.is( textile.convert( tx ), + "

    \"test\"

    \n\ +

    Regular paragraph.

    \n\ +
    \n\ +

    This is one paragraph.

    \n\ +

    This is another.

    \n\ +

    \"\"

    \n\ +
      \n\ +\t
    • A list
    • \n\ +\t
    • in a div.
    • \n\ +
    \n\ +
    \n\ +

    Another paragraph.

    ", tx ); +}); + + +test( 'mixing of textile and XHTML', function ( t ) { + let tx = "\"test\"\n\n\ +Regular *paragraph*."; + t.is( textile.convert( tx ), + "

    \"test\"

    \n\ +

    Regular paragraph.

    ", tx ); +}); + + +test( 'wraps inline HTML in paragraphs', function ( t ) { + let tx = "asd blabla \"google\":http://google.com"; + t.is( textile.convert( tx ), + "

    asd blabla google

    ", tx ); +}); + + +test( 'self closing XHTML with following text not recognized', function ( t ) { + let tx = "
    this has been a horizontal rule"; + t.is( textile.convert( tx ), + "


    this has been a horizontal rule

    ", tx ); +}); + + +test( 'self closing HTML with following text not recognized', function ( t ) { + let tx = "
    that was a horizontal rule too"; + t.is( textile.convert( tx ), + "
    that was a horizontal rule too", tx ); +}); + + +test( 'preserves block html', function ( t ) { + let tx = "
    123 Anystreet
    \n\n\ +

    Explicit paragraph

    "; + t.is( textile.convert( tx ), + "
    123 Anystreet
    \n\ +

    Explicit paragraph

    ", tx ); +}); + + +test( 'preserves empty block standalone elements', function ( t ) { + let tx = "
    "; + t.is( textile.convert( tx ), + "
    ", tx ); +}); + + +test( 'unfinished standalone HTML', function ( t ) { + let tx = "
    \n\ +This is some div text.\n\n\ +More div text."; + t.is( textile.convert( tx ), + "
    \n\ +

    This is some div text.

    \n\ +

    More div text.

    ", tx ); +}); + + +test( 'unfinished HTML block', function ( t ) { + let tx = "
    This is some div text.\n\n\ +More div text."; + t.is( textile.convert( tx ), + "
    This is some div text.
    \n\ +
    \n\ +More div text.", tx ); +}); + + +test( 'complex example from real life', function ( t ) { + let tx = "
    \n\ +
    \n\n\ +
    \n\ +h1. Contact\n\n\ +Please contact us if you have questions or need help making arrangements.\n\n\ +
    \n\ +
    \n\n\ +
    \n\ +h2. Tom\n\n\ +(540) 555-1212\n\n\ +h3. Jerry\n\n\ +(540) 555-1234\n\n\ +
    "; + t.is( textile.convert( tx ), + "
    \n\ +
    \n\ +
    \n\ +

    Contact

    \n\ +

    Please contact us if you have questions or need help making arrangements.

    \n\ +
    \n\ +
    \n\ +
    \n\ +

    Tom

    \n\ +

    (540) 555-1212

    \n\ +

    Jerry

    \n\ +

    (540) 555-1234

    \n\ +
    ", tx ); +}); + + +test( 'embedded javascript', function ( t ) { + let tx = ""; + t.is( textile.convert( tx ), + "", tx ); +}); + + +test( 'inline embedded javascript', function ( t ) { + let tx = "Please email me at ."; + t.is( textile.convert( tx ), + "

    Please email me at .

    ", tx ); +}); + + +test( 'HTML end tag can end paragraph', function ( t ) { + let tx = "
    \n\ +This is a paragraph.\n\ +
    "; + t.is( textile.convert( tx ), + "
    \n\ +

    This is a paragraph.

    \n\ +
    ", tx ); +}); + + +test( 'HTML end tag can end blockquote', function ( t ) { + let tx = "
    \n\ +bq. This is a blockquote.\n\ +
    "; + t.is( textile.convert( tx ), + "
    \n\ +
    \n\ +

    This is a blockquote.

    \n\ +
    \n\ +
    ", tx ); +}); + + +test( 'before table does not affect table', function ( t ) { + let tx = "
    \n\n\ +h2. heading\n\n\ +|a|b|c|\n\ +|d|e|f|"; + t.is( textile.convert( tx ), + "
    \n\ +

    heading

    \n\ +\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
    abc
    def
    ", tx ); +}); + + +test( 'tilde in innerHTML is not altered', function ( t ) { + let tx = "http://foo.com/bar?something=1~2~3"; + t.is( textile.convert( tx ), + "

    http://foo.com/bar?something=1~2~3

    ", tx ); +}); + + +test( 'empty block', function ( t ) { + let tx = "
    "; + t.is( textile.convert( tx ), + "
    ", tx ); +}); + + +test( 'in code escaped properly', function ( t ) { + let tx = "
    some bold text
    "; + t.is( textile.convert( tx ), + "
    some <b>bold</b> text
    ", tx ); +}); + + +test( 'in code with class attribute escaped properly', function ( t ) { + let tx = "
    some bold text
    "; + t.is( textile.convert( tx ), + "
    some <b>bold</b> text
    ", tx ); +}); + + +test( 'notextile beginning the line', function ( t ) { + let tx = "Sir Bobby Robson, is a famous footballer"; + t.is( textile.convert( tx ), + "

    Sir Bobby Robson, is a famous footballer

    ", tx ); +}); + + +test( 'br tag with class', function ( t ) { + let tx = "br(clear). "; + t.is( textile.convert( tx ), + "
    ", tx ); +}); + + +test( 'hr tag with class', function ( t ) { + let tx = "hr(clear). "; + t.is( textile.convert( tx ), + "
    ", tx ); +}); diff --git a/test/images.js b/test/images.js new file mode 100644 index 0000000..3a60c70 --- /dev/null +++ b/test/images.js @@ -0,0 +1,521 @@ +// images.yml +import test from 'ava'; +import textile from '../src'; + +test( 'images:1', function ( t ) { + let tx = "This is an !image.jpg!"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:2', function ( t ) { + let tx = "This is an !image.jpg(with alt text)!"; + t.is( textile.convert( tx ), + "

    This is an

    ", tx ); +}); + + +test( 'images:3', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:4', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg#a1!"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:5', function ( t ) { + let tx = "This is an !image.jpg!."; + t.is( textile.convert( tx ), + "

    This is an \"\".

    ", tx ); +}); + + +test( 'images:6', function ( t ) { + let tx = "This is an !image.jpg(with alt text)!."; + t.is( textile.convert( tx ), + "

    This is an .

    ", tx ); +}); + + +test( 'images:7', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!."; + t.is( textile.convert( tx ), + "

    This is an \"\".

    ", tx ); +}); + + +test( 'images:8', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg#a1!."; + t.is( textile.convert( tx ), + "

    This is an \"\".

    ", tx ); +}); + + +test( 'images:9', function ( t ) { + let tx = "This is not an image!!!"; + t.is( textile.convert( tx ), + "

    This is not an image!!!

    ", tx ); +}); + + +test( 'images:10', function ( t ) { + let tx = "This is not an! image!"; + t.is( textile.convert( tx ), + "

    This is not an! image!

    ", tx ); +}); + + +test( 'images:11', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:#1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:12', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:#a"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:13', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:#a1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:14', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:#a10"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:15', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:index.html"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:16', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:index.html#1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:17', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:index.html#a1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:18', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:index.html#a10"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:19', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:index.html?foo=bar"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:20', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:index.html?foo=bar#1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:21', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:index.html?foo=bar#a"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:22', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:index.html?foo=bar#a1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:23', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:index.html?foo=bar#a10"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:24', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:25', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/#1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:26', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/#a"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:27', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/#a1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:28', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/#a10"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:29', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:30', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html#1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:31', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html#a"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:32', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html#a1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:33', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html#a10"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:34', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:35', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar#1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:36', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar#a"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:37', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar#a1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:38', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar#a10"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:39', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:40', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:41', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:42', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a1"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:43', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a10"; + t.is( textile.convert( tx ), + "

    This is an \"\"

    ", tx ); +}); + + +test( 'images:44', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b."; + t.is( textile.convert( tx ), + "

    This is an \"\".

    ", tx ); +}); + + +test( 'images:45', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#1."; + t.is( textile.convert( tx ), + "

    This is an \"\".

    ", tx ); +}); + + +test( 'images:46', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a."; + t.is( textile.convert( tx ), + "

    This is an \"\".

    ", tx ); +}); + + +test( 'images:47', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a1."; + t.is( textile.convert( tx ), + "

    This is an \"\".

    ", tx ); +}); + + +test( 'images:48', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a10."; + t.is( textile.convert( tx ), + "

    This is an \"\".

    ", tx ); +}); + + +test( 'images:49', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b, but this is not."; + t.is( textile.convert( tx ), + "

    This is an \"\", but this is not.

    ", tx ); +}); + + +test( 'images:50', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#1, but this is not."; + t.is( textile.convert( tx ), + "

    This is an \"\", but this is not.

    ", tx ); +}); + + +test( 'images:51', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a, but this is not."; + t.is( textile.convert( tx ), + "

    This is an \"\", but this is not.

    ", tx ); +}); + + +test( 'images:52', function ( t ) { + let tx = "This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a1, but this is not."; + t.is( textile.convert( tx ), + "

    This is an \"\", but this is not.

    ", tx ); +}); + + +test( 'images:53', function ( t ) { + let tx = "(This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a10) This is not."; + t.is( textile.convert( tx ), + "

    (This is an \"\") This is not.

    ", tx ); +}); + + +test( 'images:54', function ( t ) { + let tx = "(This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b) This is not."; + t.is( textile.convert( tx ), + "

    (This is an \"\") This is not.

    ", tx ); +}); + + +test( 'images:55', function ( t ) { + let tx = "(This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#1) This is not."; + t.is( textile.convert( tx ), + "

    (This is an \"\") This is not.

    ", tx ); +}); + + +test( 'images:56', function ( t ) { + let tx = "(This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a) This is not."; + t.is( textile.convert( tx ), + "

    (This is an \"\") This is not.

    ", tx ); +}); + + +test( 'images:57', function ( t ) { + let tx = "(This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a1) This is not."; + t.is( textile.convert( tx ), + "

    (This is an \"\") This is not.

    ", tx ); +}); + + +test( 'images:58', function ( t ) { + let tx = "(This is an !http://example.com/i/image.jpg!:http://example.com/index.html?foo=bar&a=b#a10) This is not."; + t.is( textile.convert( tx ), + "

    (This is an \"\") This is not.

    ", tx ); +}); + + +test( 'image with relative src with dot', function ( t ) { + let tx = "!../../image.jpg!"; + t.is( textile.convert( tx ), + "

    \"\"

    ", tx ); +}); + + +test( 'image with class', function ( t ) { + let tx = "!(myclass)image.jpg!"; + t.is( textile.convert( tx ), + "

    \"\"

    ", tx ); +}); + + +test( 'image with class and dotspace', function ( t ) { + let tx = "!(myclass). image.jpg!"; + t.is( textile.convert( tx ), + "

    \"\"

    ", tx ); +}); + + +test( 'image with class and relative src with dots', function ( t ) { + let tx = "!(myclass)../../image.jpg!"; + t.is( textile.convert( tx ), + "

    \"\"

    ", tx ); +}); + + +test( 'image with class and dotspace and relative src with dots', function ( t ) { + let tx = "!(myclass). ../../image.jpg!"; + t.is( textile.convert( tx ), + "

    \"\"

    ", tx ); +}); + + +test( 'image with style', function ( t ) { + let tx = "!{color:red}image.jpg!"; + t.is( textile.convert( tx ), + "

    \"\"

    ", tx ); +}); + + +test( 'image with style and dotspace', function ( t ) { + let tx = "!{color:red}. image.jpg!"; + t.is( textile.convert( tx ), + "

    \"\"

    ", tx ); +}); + + +test( 'image attributes has ampersand html entity in alt and title', function ( t ) { + let tx = "!/pictures/cat_and_fox.jpg(Trady Blix & The cartoon fox)!"; + t.is( textile.convert( tx ), + "

    \"Trady

    ", tx ); +}); + + +test( 'image attributes has double quote html entity in alt and title', function ( t ) { + let tx = "!/pictures/bacon.jpg(The fox said: \"Have some chunky bacon\")!"; + t.is( textile.convert( tx ), + "

    \"The

    ", tx ); +}); + + +test( 'image attributes has single quote html entity in alt and title', function ( t ) { + let tx = "!/pictures/bacon.jpg(The fox said: 'Have some chunky bacon')!"; + t.is( textile.convert( tx ), + "

    \"The

    ", tx ); +}); + + +test( 'in square brackets', function ( t ) { + let tx = "This is an [!image.jpg!] you see."; + t.is( textile.convert( tx ), + "

    This is an \"\" you see.

    ", tx ); +}); + + +test( 'with link in square brackets', function ( t ) { + let tx = "This is an [!image.jpg!:http://example.com/] you see."; + t.is( textile.convert( tx ), + "

    This is an \"\" you see.

    ", tx ); +}); + + +test( 'url containing parentheses', function ( t ) { + let tx = "!http://commons.wikimedia.org/wiki/File:Rubis_sur_calcite_2(Vietnam).jpg!"; + t.is( textile.convert( tx ), + "

    \"\"

    ", tx ); +}); + + +test( 'with alt and url containing parentheses', function ( t ) { + let tx = "!http://commons.wikimedia.org/wiki/File:Rubis_sur_calcite_2(Vietnam).jpg(a big rock)!"; + t.is( textile.convert( tx ), + "

    \"a

    ", tx ); +}); + + +test( 'with link that contains parentheses', function ( t ) { + let tx = "!image.jpg(Alt text with (parentheses).)!"; + t.is( textile.convert( tx ), + "

    \"Alt

    ", tx ); +}); + + +test( 'with link and title and text afterward', function ( t ) { + let tx = "!/image_r.jpg(description)!:image.jpg text."; + t.is( textile.convert( tx ), + "

    \"description\" text.

    ", tx ); +}); + diff --git a/test/index.html b/test/index.html deleted file mode 100644 index 0b18baa..0000000 --- a/test/index.html +++ /dev/null @@ -1,41 +0,0 @@ - - - - - - textile tests - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    textile tests

    -

    -

    -
      - - diff --git a/test/index.js b/test/index.js deleted file mode 100644 index 3717af2..0000000 --- a/test/index.js +++ /dev/null @@ -1,199 +0,0 @@ -/* - * This file implements a subset of the QUnit functions/features to allow - * running simple QUnit tests in Node.JS. - * - * Copyright (c) 2012 Borgar Þorsteinsson - * Licensed under the terms of the MIT (LICENSE.txt) software license. - * - */ - -// set up environment: -var textile = require('../lib/textile.js'); - -// add some test files: -var $testfiles = [ - 'converted/basic.js', -// 'converted/code.js', - 'converted/definitions.js', - 'converted/extra_whitespace.js', - 'converted/filter_pba.js', -// 'converted/html.js', - 'converted/images.js', -// 'converted/instiki.js', - 'converted/lists.js', - 'converted/links.js', - 'converted/poignant.js', - 'converted/table.js', - 'tables-extended.js', - 'converted/textism.js', - 'converted/threshold.js', - 'block_comments.js', - 'jstextile-tests.js', - 'linebreaks.js', - 'options.js' -]; - - -/* -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- */ - -var $tests = []; -$tests.current_test; - -function expect ( num ) { - $tests.current_test.expected = num; -} - -function ok ( value, message ) { - $tests.current_test.results.push([ !!value, message ]); -} - -function equal ( rest, exp, msg ) { - try { - require('assert').equal(rest, exp); - } - catch ( err ) { - $tests.current_test.results.push([ false, msg + ', expected: ' + exp + ' result: ' + rest ]); - return; - } - $tests.current_test.results.push([ true, msg ]); -} - -function deepEqual ( rest, exp, msg ) { - try { - require('assert').deepEqual(rest, exp); - } - catch ( err ) { - $tests.current_test.results.push([ false, msg + ', expected: ' + exp + ' result: ' + rest ]); - return; - } - $tests.current_test.results.push([ true, msg ]); -} - -function test ( testName /*, expected, callback, async */ ) { - - var tmap = { - 'object':'environment', - 'boolean':'async', - 'function':'callback', - 'number':'expected' - }; - - $tests.current_test = { - name: testName, - expected: null, - callback: null, - context: {}, - async: false, // TODO: async doesn't actually do anything :-/ - error: false, - results: [] - }; - $tests.push( $tests.current_test ); - - for (var i=1,l=arguments.length; iJoe Bob?, this should all be in italic!_"; + t.is( textile.convert( tx ), + "

      Hi, Joe Bob?, this should all be in italic!

      ", tx ); +}); + + +test( 'instiki:2', function ( t ) { + let tx = "*this span is strong*"; + t.is( textile.convert( tx ), + "

      this span is strong

      ", tx ); +}); + + +test( 'instiki:3', function ( t ) { + let tx = "*this Camel Thing? is strong*"; + t.is( textile.convert( tx ), + "

      this Camel Thing? is strong

      ", tx ); +}); + + +test( 'instiki:4', function ( t ) { + let tx = "_this span is italic_"; + t.is( textile.convert( tx ), + "

      this span is italic

      ", tx ); +}); + + +/*test( 'instiki:5', function ( t ) { + let tx = "%{color:red}nested span because of Camel Word?%"; + t.is( textile.convert( tx ), + "

      nested span because of Camel Word?

      ", tx ); +});*/ + + +test( 'instiki:6', function ( t ) { + let tx = "h2. Version History\n\n\ +* \"Version\n\ +0.0\":http://www.threewordslong.com/render-0-8-9b.patch - Early version using MD5 hashes.\n\ +* \"Version\n\ +0.1\":http://www.threewordslong.com/chunk-0-1.patch.gz - First cut of new system. Much cleaner.\n\ +* \"Version 0.2\":http://www.threewordslong.com/chunk-0-2.patch.gz - Fixed problem with \"authors\" page and some tests."; + t.is( textile.convert( tx ), + "

      Version History

      \n\ +", tx ); +}); + + +test( 'instiki:7', function ( t ) { + let tx = "--richSeymour --whyTheLuckyStiff"; + t.is( textile.convert( tx ), + "

      —richSeymour —whyTheLuckyStiff

      ", tx ); +}); diff --git a/test/jstextile-tests.js b/test/jstextile-tests.js deleted file mode 100644 index 75ffbb0..0000000 --- a/test/jstextile-tests.js +++ /dev/null @@ -1,751 +0,0 @@ -test('jstextile', function () { - - - -equal(textile.convert( // HTML blockquote spanning paragraphs - - "A line break delimited block quote:\n"+ - "\n"+ - "
      \n"+ - "How unbearable at times are people who are happy, people for whom everything works out.\n"+ - "\n"+ - "Anton Pavlovich Chekhov - 1860-1904\n"+ - "
      " - -), // Should output - - "

      A line break delimited block quote:

      \n"+ - "
      \n"+ - "

      How unbearable at times are people who are happy, people for whom everything works out.

      \n"+ - "

      Anton Pavlovich Chekhov – 1860-1904

      \n"+ - "
      " - -); - - -equal(textile.convert( // User has mistaken list format for markdowns - -"Here a tricky list\n"+ -"\n"+ -"* item1\n"+ -" * item2\n"+ -"* item3\n"+ -"* item4\n"+ -"\n"+ -"Tailing line." - -), // Should output - -"

      Here a tricky list

      \n"+ -"
        \n"+ -"\t
      • item1
      • \n"+ -"\t
      • item2
      • \n"+ -"\t
      • item3
      • \n"+ -"\t
      • item4
      • \n"+ -"
      \n"+ -"

      Tailing line.

      " - -); - - -equal(textile.convert( // HTML list - -"Your inventory:\n"+ -"\n"+ -"
        \n"+ -"
      • Lamp
      • \n"+ -"
      • Napkin
      • \n"+ -"
      • Sword
      • \n"+ -"
      • Plastic Cup
      • \n"+ -"
      " - -), // Should output - -"

      Your inventory:

      \n"+ -"
        \n"+ -"
      • Lamp
      • \n"+ -"
      • Napkin
      • \n"+ -"
      • Sword
      • \n"+ -"
      • Plastic Cup
      • \n"+ -"
      " - -); - - - -equal(textile.convert( // Span with an ending percentage - -"span %percent 10%% of stuff" - -), // Should output - -"

      span percent 10% of stuff

      " - -); - - - -equal(textile.convert( // arrow glyph - -"-> arrow" - -), // Should output - -"

      → arrow

      " - -); - - - -equal(textile.convert( // Span with an ending percentage - -"|a|b|\n"+ -"|a|b| " - -), // Should output - -"\n"+ -"\t\n"+ -"\t\t\n"+ -"\t\t\n"+ -"\t\n"+ -"\t\n"+ -"\t\t\n"+ -"\t\t\n"+ -"\t\n"+ -"
      ab
      ab
      " - -); - - - -equal(textile.convert( // clean trademarks #1 - -"(TM) and (tm), but not (Tm) or (tM)" - -), // Should output - -"

      ™ and ™, but not (Tm) or (tM)

      " - -); - - - -equal(textile.convert( // clean trademarks #2 - -"(TM) and [TM], but not (TM] or [TM)" - -), // Should output - -"

      ™ and ™, but not (TM] or [TM)

      " - -); - - - -equal(textile.convert( // escaping works in tables - -"| cat > sed | awk ==|== less |\n"+ -"| 1234 | 2345 |" - -), // Should output - -"\n"+ -"\t\n"+ -"\t\t\n"+ -"\t\t\n"+ -"\t\n"+ -"\t\n"+ -"\t\t\n"+ -"\t\t\n"+ -"\t\n"+ -"
      cat > sed awk | less
      1234  2345
      " - -); - - - -/* - Don't know about this. This doesn't work in RC or some other implementations. - I do expect things to work as test shows. It's disabled for now... -*/ -/* -equal(textile.convert( - -"__test_" - -), // Should output - -"

      _test

      " - -); -*/ - -/* - Both RC and PHP do crazy things when faced with something like this. - While it IS bizarre input, we should still try to stay in control. -*/ -equal(textile.convert( // Strange list - -"* a\n"+ -"*** b\n"+ -"** c\n"+ -"*** d" - -), // Should output - -"
        \n"+ -"\t
      • a\n"+ -"\t
          \n"+ -"\t\t
        • \n"+ -"\t\t
            \n"+ -"\t\t\t
          • b
          • \n"+ -"\t\t
        • \n"+ -"\t\t
        • c\n"+ -"\t\t
            \n"+ -"\t\t\t
          • d
          • \n"+ -"\t\t
        • \n"+ -"\t
      • \n"+ -"
      " - -); - - - -/* - -RedCloth deviates from PHP in that it only allows [] fences. -This is good as the design gets less messy. But it causes problems as fencing links -then fails with PHP-style array links. - -I guess this is why the original used two fencing styles. - -*/ -equal(textile.convert( // Fenced PHP-style array link - -'["PHP array link":http://example.com/?foo[]=wewe]' - -), // Should output - -'

      PHP array link

      ' - -); -equal(textile.convert( // Fenced PHP-style array link - -'["PHP array link":http://example.com/?foo[1]=wewe]' - -), // Should output - -'

      PHP array link

      ' - -); -equal(textile.convert( // Fenced PHP-style array link - -'["PHP array link":http://example.com/?foo[a]=wewe]' - -), // Should output - -'

      PHP array link

      ' - -); - - - -equal(textile.convert( // HTML comment - -'line\n'+ -'\n'+ -'line' - -), // Should output - -"

      line
      \n"+ -"
      \n"+ -"line

      " - -); - - - - -equal(textile.convert( - -"line\n"+ -"\n"+ -"\n"+ -"\n"+ -"line" - -), // Should output - -"

      line

      \n"+ -"\n"+ -"

      line

      " - -); - - - -equal(textile.convert( - -"REYKJAVÍK" - -), // Should output - -"

      REYKJAVÍK

      " - -); - - - -equal(textile.convert( // Multiple classes - - "p(first second). some text" - -), // Should output - - "

      some text

      " - -,"2 css classes"); - - - -equal(textile.convert( // Multiple classes - - "p(first second third). some text" - -), // Should output - - "

      some text

      " - -,"3 css classes"); - - - -equal(textile.convert( // Multiple classes - - "p(first second third#someid). some text" - -), // Should output - - "

      some text

      " - -,"3 css classes + id"); - - -equal(textile.convert( // Multiple classes - - "\"(foo bar) text (link title)\":http://example.com/" - -), // Should output - - "

      text

      " - -,"2 classes + title on a link"); - - -equal(textile.convert( // Multiple classes - - "| a |(eee fee). b |\n"+ - "| a |( b )|" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
      a b
      a ( b )
      " - -,"dual classes on table cells"); - - - - -equal(textile.convert( // Multiple classes - - "_(span)_\n"+ - "_(span span)_\n"+ - "_(span) span_\n"+ - "_(span) span (span)_\n"+ - "_(span span) span (span span)_" - -), // Should output - - "

      (span)
      \n"+ - "(span span)
      \n"+ - "(span) span
      \n"+ - "(span) span (span)
      \n"+ - "(span span) span (span span)

      " - -,"spans in parens"); - - -equal(textile.convert( // Multiple classes - - "_{display:block}(span) span (span)_" - -), // Should output - - "

      (span) span (span)

      " - -,"partal attr span parse"); - - -equal(textile.convert( // inline code with leading @ - - "a @@var@ test" - -), // Should output - - "

      a @var test

      " - -,"inline code with leading @"); - - - -equal(textile.convert( // inline code with a single @ - - "a @@@ test" - -), // Should output - - "

      a @ test

      " - -,"inline code with a single @"); - - - -equal(textile.convert( // empty block 1 - - "h1." - -), // Should output - - "

      h1.

      " - -,"empty block #1"); - - - -equal(textile.convert( // empty block 2 - - "h1. " - -), // Should output - - "

      " - -,"empty block #2"); - - -equal(textile.convert( // empty block 3 - - "h1{display:block}. " - -), // Should output - - '

      ' - -,"empty block #3"); - -equal(textile.convert( // non list 1 - - "*" - -), // Should output - - "

      *

      " - -,"non list #1"); - -equal(textile.convert( // non list 2 - - "#" - -), // Should output - - "

      #

      " - -,"non list #2"); - -equal(textile.convert( // non list 3 - - "*\n" - -), // Should output - - "

      *

      " - -,"non list #3"); - -equal(textile.convert( // non list 4 - - "#\n" - -), // Should output - - "

      #

      " - -,"non list #4"); - -equal(textile.convert( // non list 5 - - "*\ntest" - -), // Should output - - "

      *
      \ntest

      " - -,"non list #5"); - -equal(textile.convert( // empty list 1 - - "* \n" - -), // Should output - - "

      *

      " - -,"empty list #1"); - -equal(textile.convert( // empty list 2 - - "# \n" - -), // Should output - - "

      #

      " - -,"empty list #2"); - -equal(textile.convert( // insert empty list 1 - - "*\n\ntest" - -), // Should output - - "

      *

      \n

      test

      " - -,"insert empty list #1"); - -equal(textile.convert( // insert empty list 2 - - "#\n\ntest" - -), // Should output - - "

      #

      \n

      test

      " - -,"insert empty list #2"); - - -equal(textile.convert( // empty attributes (1) - - '' - -), // Should output - - '

      ' - -,"empty attributes (1)"); - - - -equal(textile.convert( // empty attributes (2) - - '' - -), // Should output - - '

      ' - -,"empty attributes (2)"); - - - -equal(textile.convert( // bold line vs. list - - '*{color:red}bold red*' - -), // Should output - - '

      bold red

      ' - -,"bold line vs. list"); - - -equal(textile.convert( // strict list matching (1) - - '*{color:red} item*\n\n'+ - '* item*\n\n'+ - '*item*' - -), // Should output - - '
        \n'+ - '\t
      • item*
      • \n'+ - '
      \n'+ - '
        \n'+ - '\t
      • item*
      • \n'+ - '
      \n'+ - '

      item

      ' - -,"strict list matching (1)"); - -equal(textile.convert( // strict list matching (2) - - '*{color:red} item\n\n'+ - '* item\n\n'+ - '*item' - -), // Should output - - '
        \n'+ - '\t
      • item
      • \n'+ - '
      \n'+ - '
        \n'+ - '\t
      • item
      • \n'+ - '
      \n'+ - '

      *item

      ' - -,"strict list matching (2)"); - - - - -var t1 = Date.now(); -textile.convert("!a()aaaaaaaaaaaaaaaaaaaaaaaaaa"); -var t2 = Date.now(); -ok( ( t2 - t1 < 10 ), 'image parsing speed bug' ); - - - - - -/* parse inline textile in footnotes */ - -equal(textile.convert( // The textile - - "fn1. This is _emphasized_ *strong*" - -), // Should output - - "

      1 This is emphasized strong

      " - -,"footnote inline textile"); - - - - -/* greedy globbing block parser bug [#21] */ - -equal(textile.convert( // The textile - - "pab\n\npabcde\n\nbqabcdef\n\nlast line ending in period+space. \n" - -), // Should output - - '

      pab

      \n'+ - '

      pabcde

      \n'+ - '

      bqabcdef

      \n'+ - '

      last line ending in period+space.

      ' - -,"block parser bug (#21)"); - - - - -/* trailing space linebreak bug [#26] */ - -equal(textile.convert( // The textile - - "Line 1 \nLine 2\nLine 3" - -), // Should output - - '

      Line 1
      \nLine 2
      \nLine 3

      ' - -,"trailing space linebreak bug (#26)"); - - -/* support unicode symbols */ - -equal(textile.convert( // The textile - - "Trademark(tm)\n\ -Registered(R)\n\ -Copyright (C) 2008\n\ -One quarter (1/4) symbol\n\ -One half (1/2) symbol\n\ -Three quarters (3/4) symbol\n\ -Degree (o) symbol\n\ -Plus/minus (+/-) symbol" - -), // Should output - - '

      Trademark™
      \n\ -Registered®
      \n\ -Copyright © 2008
      \n\ -One quarter ¼ symbol
      \n\ -One half ½ symbol
      \n\ -Three quarters ¾ symbol
      \n\ -Degree ° symbol
      \n\ -Plus/minus ± symbol

      ' - -,"support unicode symbols (#27)"); - - - - -/* footnotes should not appear directly inside tags [#28] */ - -equal(textile.convert( // The textile - - "*[1234]* _[1234]_" - -), // Should output - - '

      [1234] [1234]

      ' - -,"footnotes should not appear directly inside tags (#26)"); - - - -/* footnotes have to directly follow text [#28] */ - -equal(textile.convert( // The textile - - "[1234]" - -), // Should output - - '

      [1234]

      ' - -,"footnotes have to directly follow text (#26)"); - - - - -/* footnote links can be disabled with ! */ - -equal(textile.convert( // The textile - - "foobar[1234!]" - -), // Should output - - '

      foobar1234

      ' - -,"footnote links can be disabled with !"); - - - - - -}); diff --git a/test/jstextile.js b/test/jstextile.js new file mode 100644 index 0000000..1ad708e --- /dev/null +++ b/test/jstextile.js @@ -0,0 +1,438 @@ +/*eslint quotes:0*/ +/*eslint no-multiple-empty-lines:0*/ +import test from 'ava'; +import textile from '../src'; + +test( 'HTML blockquote spanning paragraphs', function ( t ) { + t.is( textile.convert( + "A line break delimited block quote:\n\n" + + "
      \n" + + "How unbearable at times are people who are happy, people for whom everything works out.\n\n" + + "Anton Pavlovich Chekhov - 1860-1904\n" + + "
      " ), + "

      A line break delimited block quote:

      \n" + + "
      \n" + + "

      How unbearable at times are people who are happy, people for whom everything works out.

      \n" + + "

      Anton Pavlovich Chekhov – 1860-1904

      \n" + + "
      " ); +}); + +test( 'User has mistaken list format for markdowns', function ( t ) { + t.is( textile.convert( + "Here a tricky list\n\n" + + "* item1\n" + + " * item2\n" + + "* item3\n" + + "* item4\n\n" + + "Tailing line." ), + "

      Here a tricky list

      \n" + + "
        \n" + + "\t
      • item1
      • \n" + + "\t
      • item2
      • \n" + + "\t
      • item3
      • \n" + + "\t
      • item4
      • \n" + + "
      \n" + + "

      Tailing line.

      " ); +}); + +test( 'HTML list', function ( t ) { + t.is( textile.convert( + "Your inventory:\n\n" + + "
        \n" + + "
      • Lamp
      • \n" + + "
      • Napkin
      • \n" + + "
      • Sword
      • \n" + + "
      • Plastic Cup
      • \n" + + "
      " ), + "

      Your inventory:

      \n" + + "
        \n" + + "
      • Lamp
      • \n" + + "
      • Napkin
      • \n" + + "
      • Sword
      • \n" + + "
      • Plastic Cup
      • \n" + + "
      " ); +}); + +test( 'Span with an ending percentage', function ( t ) { + t.is( textile.convert( "span %percent 10%% of stuff" ), + "

      span percent 10% of stuff

      " ); +}); + +test( 'Arrow glyph', function ( t ) { + t.is( textile.convert( "-> arrow" ), "

      → arrow

      " ); +}); + +test( 'Simple table with tailing space', function ( t ) { + t.is( textile.convert( "|a|b|\n|a|b| " ), + "\n" + + "\t\n" + + "\t\t\n" + + "\t\t\n" + + "\t\n" + + "\t\n" + + "\t\t\n" + + "\t\t\n" + + "\t\n" + + "
      ab
      ab
      " ); +}); + + +test( 'clean trademarks #1', function ( t ) { + t.is( textile.convert( "(TM) and (tm), but not (Tm) or (tM)" ), + "

      ™ and ™, but not (Tm) or (tM)

      " ); +}); + + +test( 'clean trademarks #3', function ( t ) { + t.is( textile.convert( "(TM) and [TM], but not (TM] or [TM)" ), + "

      ™ and ™, but not (TM] or [TM)

      " ); +}); + + +test( 'clean trademarks #3', function ( t ) { + // escaping works in tables + t.is( textile.convert( "| cat > sed | awk ==|== less |\n| 1234 | 2345 |" ), + "\n" + + "\t\n" + + "\t\t\n" + + "\t\t\n" + + "\t\n" + + "\t\n" + + "\t\t\n" + + "\t\t\n" + + "\t\n" + + "
      cat > sed awk | less
      1234 2345
      " ); +}); + + +// Don't know about this. This doesn't work in RC or some other implementations. +// I do expect things to work as test shows. It's disabled for now... +/* +test( '__test_', function ( t ) { + t.is( textile.convert( "__test_" ), "

      _test

      " ); +}); +*/ + +// Both RC and PHP do crazy things when faced with something like this. +// While it IS bizarre input, we should still try to stay in control. +test( 'Strange list', function ( t ) { + t.is( textile.convert( + "* a\n" + + "*** b\n" + + "** c\n" + + "*** d" ), + "
        \n" + + "\t
      • a\n" + + "\t
          \n" + + "\t\t
        • \n" + + "\t\t
            \n" + + "\t\t\t
          • b
          • \n" + + "\t\t
        • \n" + + "\t\t
        • c\n" + + "\t\t
            \n" + + "\t\t\t
          • d
          • \n" + + "\t\t
        • \n" + + "\t
      • \n" + + "
      " ); +}); + + +// RedCloth deviates from PHP in that it only allows [] fences. +// This is good as the design gets less messy. But it causes problems as fencing links +// then fails with PHP-style array links. +// +// I guess this is why the original used two fencing styles. +test( 'Fenced PHP-style array link (1)', function ( t ) { + t.is( textile.convert( '["PHP array link":http://example.com/?foo[]=wewe]' ), + '

      PHP array link

      ' ); +}); +test( 'Fenced PHP-style array link (2)', function ( t ) { + t.is( textile.convert( '["PHP array link":http://example.com/?foo[1]=wewe]' ), + '

      PHP array link

      ' ); +}); +test( 'Fenced PHP-style array link (3)', function ( t ) { + t.is( textile.convert( '["PHP array link":http://example.com/?foo[a]=wewe]' ), + '

      PHP array link

      ' ); +}); + + +test( 'HTML comment (1)', function ( t ) { + t.is( textile.convert( 'line\n\nline' ), + "

      line
      \n" + + "
      \n" + + "line

      " ); +}); + +test( 'HTML comment (2)', function ( t ) { + t.is( textile.convert( "line\n\n\n\nline" ), + "

      line

      \n" + + "\n" + + "

      line

      " ); +}); + + +test( 'ALL CAPS', function ( t ) { + t.is( textile.convert( "REYKJAVÍK" ), + "

      REYKJAVÍK

      " ); +}); + + +test( 'Multiple classes', function ( t ) { + t.is( textile.convert( "p(first second). some text" ), + "

      some text

      ", + "2 css classes" ); +}); + +test( 'Multiple classes', function ( t ) { + t.is( textile.convert( "p(first second third). some text" ), + "

      some text

      ", + "3 css classes" ); +}); + +test( 'Multiple classes', function ( t ) { + t.is( textile.convert( "p(first second third#someid). some text" ), + "

      some text

      ", + "3 css classes + id" ); +}); + +test( 'Multiple classes', function ( t ) { + t.is( textile.convert( "\"(foo bar) text (link title)\":http://example.com/" ), + "

      text

      ", + "2 classes + title on a link" ); +}); + +test( 'Multiple classes', function ( t ) { + t.is( textile.convert( "| a |(eee fee). b |\n| a |( b )|" ), + "\n" + + "\t\n" + + "\t\t\n" + + "\t\t\n" + + "\t\n" + + "\t\n" + + "\t\t\n" + + "\t\t\n" + + "\t\n" + + "
      a b
      a ( b )
      ", + "dual classes on table cells" ); +}); + +test( 'Multiple classes', function ( t ) { + t.is( textile.convert( + "_(span)_\n" + + "_(span span)_\n" + + "_(span) span_\n" + + "_(span) span (span)_\n" + + "_(span span) span (span span)_" ), + "

      (span)
      \n" + + "(span span)
      \n" + + "(span) span
      \n" + + "(span) span (span)
      \n" + + "(span span) span (span span)

      ", + "spans in parens" ); +}); + +test( 'Multiple classes', function ( t ) { + t.is( textile.convert( "_{display:block}(span) span (span)_" ), + "

      (span) span (span)

      ", + "partal attr span parse" ); +}); + +test( 'inline code with leading @', function ( t ) { + t.is( textile.convert( "a @@var@ test" ), + "

      a @var test

      ", + "inline code with leading @" ); +}); + +test( 'inline code with a single @', function ( t ) { + t.is( textile.convert( "a @@@ test" ), + "

      a @ test

      ", + "inline code with a single @" ); +}); + +test( 'empty block 1', function ( t ) { + t.is( textile.convert( "h1." ), + "

      h1.

      ", + "empty block #1" ); +}); + +test( 'empty block 2', function ( t ) { + t.is( textile.convert( "h1. " ), + "

      ", + "empty block #2" ); +}); + +test( 'empty block 3', function ( t ) { + t.is( textile.convert( "h1{display:block}. " ), + '

      ', + "empty block #3" ); +}); + +test( 'non list 1', function ( t ) { + t.is( textile.convert( "*" ), + "

      *

      ", + "non list #1" ); +}); + +test( 'non list 2', function ( t ) { + t.is( textile.convert( "#" ), + "

      #

      ", + "non list #2" ); +}); + +test( 'non list 3', function ( t ) { + t.is( textile.convert( "*\n" ), + "

      *

      ", + "non list #3" ); +}); + +test( 'non list 4', function ( t ) { + t.is( textile.convert( "#\n" ), + "

      #

      ", + "non list #4" ); +}); + +test( 'non list 5', function ( t ) { + t.is( textile.convert( "*\ntest" ), + "

      *
      \ntest

      ", + "non list #5" ); +}); + +test( 'empty list 1', function ( t ) { + t.is( textile.convert( "* \n" ), + "

      *

      ", + "empty list #1" ); +}); + +test( 'empty list 2', function ( t ) { + t.is( textile.convert( "# \n" ), + "

      #

      ", + "empty list #2" ); +}); + +test( 'insert empty list 1', function ( t ) { + t.is( textile.convert( "*\n\ntest" ), + "

      *

      \n

      test

      ", + "insert empty list #1" ); +}); + +test( 'insert empty list 2', function ( t ) { + t.is( textile.convert( "#\n\ntest" ), + "

      #

      \n

      test

      ", + "insert empty list #2" ); +}); + +test( 'empty attributes (1)', function ( t ) { + t.is( textile.convert( '' ), + '

      ', + "empty attributes (1)" ); +}); + +test( 'empty attributes (2)', function ( t ) { + t.is( textile.convert( '' ), + '

      ', + "empty attributes (2)" ); +}); + +test( 'bold line vs. list', function ( t ) { + t.is( textile.convert( '*{color:red}bold red*' ), + '

      bold red

      ', + "bold line vs. list" ); +}); + +test( 'strict list matching (1)', function ( t ) { + t.is( textile.convert( + '*{color:red} item*\n\n' + + '* item*\n\n' + + '*item*' ), + '
        \n' + + '\t
      • item*
      • \n' + + '
      \n' + + '
        \n' + + '\t
      • item*
      • \n' + + '
      \n' + + '

      item

      ', + "strict list matching (1)" ); +}); + +test( 'strict list matching (2)', function ( t ) { + t.is( textile.convert( + '*{color:red} item\n\n' + + '* item\n\n' + + '*item' ), + '
        \n' + + '\t
      • item
      • \n' + + '
      \n' + + '
        \n' + + '\t
      • item
      • \n' + + '
      \n' + + '

      *item

      ', + "strict list matching (2)" ); +}); + + +test( 'image parsing speed bug', function ( t ) { + var t1 = Date.now(); + textile.convert( "!a()aaaaaaaaaaaaaaaaaaaaaaaaaa" ); + var t2 = Date.now(); + t.true( ( t2 - t1 < 10 ) ); +}); + + +test( 'parse inline textile in footnotes', function ( t ) { + t.is( textile.convert( "fn1. This is _emphasized_ *strong*" ), + "

      1 This is emphasized strong

      ", + "footnote inline textile" ); +}); + +// greedy globbing block parser bug [#21] +test( 'block parser bug (#21)', function ( t ) { + t.is( textile.convert( "pab\n\npabcde\n\nbqabcdef\n\nlast line ending in period+space. \n" ), + '

      pab

      \n' + + '

      pabcde

      \n' + + '

      bqabcdef

      \n' + + '

      last line ending in period+space.

      ' ); +}); + + +test( 'trailing space linebreak bug (#26)', function ( t ) { + t.is( textile.convert( "Line 1 \nLine 2\nLine 3" ), + '

      Line 1
      \nLine 2
      \nLine 3

      ' ); +}); + + +test( 'support unicode symbols (#27)', function ( t ) { + t.is( textile.convert( + "Trademark(tm)\n" + + "Registered(R)\n" + + "Copyright (C) 2008\n" + + "One quarter (1/4) symbol\n" + + "One half (1/2) symbol\n" + + "Three quarters (3/4) symbol\n" + + "Degree (o) symbol\n" + + "Plus/minus (+/-) symbol" ), + "

      Trademark™
      \n" + + "Registered®
      \n" + + "Copyright © 2008
      \n" + + "One quarter ¼ symbol
      \n" + + "One half ½ symbol
      \n" + + "Three quarters ¾ symbol
      \n" + + "Degree ° symbol
      \n" + + "Plus/minus ± symbol

      " ); +}); + + +test( "footnotes should not appear directly inside tags (#26)", function ( t ) { + t.is( textile.convert( "*[1234]* _[1234]_" ), + '

      [1234] [1234]

      ' ); +}); + + +test( 'footnotes have to directly follow text (#26)', function ( t ) { + t.is( textile.convert( "[1234]" ), '

      [1234]

      ' ); +}); + + +test( 'footnote links can be disabled with !', function ( t ) { + t.is( textile.convert( "foobar[1234!]" ), + '

      foobar1234

      ' ); +}); diff --git a/test/linebreaks.js b/test/linebreaks.js index 90e9f80..7e26a7a 100644 --- a/test/linebreaks.js +++ b/test/linebreaks.js @@ -1,675 +1,490 @@ -test('jstextile linebreaks', function () { - - -// converted/basic with extra CRs - -equal(textile.convert( // The textile - - "A single paragraph.\r\n"+ - "\r\n"+ - "Followed by another." - -), // Should output - - "

      A single paragraph.

      \n"+ - "

      Followed by another.

      " - -,"paragraphs"); - - -equal(textile.convert( // The textile - - "This is line one\r\n"+ - " \r\n"+ - "This is line two" - -), // Should output - - "

      This is line one

      \n"+ - "

      This is line two

      " - -,"blocks with spaces on the blank line in between"); - - -equal(textile.convert( // The textile - - "This is line one\r\n"+ - "\t\r\n"+ - "This is line two" - -), // Should output - - "

      This is line one

      \n"+ - "

      This is line two

      " - -,"blocks with tabl on the blank line in between"); - - -equal(textile.convert( // The textile - - "bq.. I saw a ship. It ate my elephant.\r\n"+ - "\r\n"+ - "When the elephant comes to take a p. you..." - -), // Should output - - "
      \n"+ - "

      I saw a ship. It ate my elephant.

      \n"+ - "

      When the elephant comes to take a p. you…

      \n"+ - "
      " - -,"extended blockquote containing block start"); - - -equal(textile.convert( // The textile - - "Some text:\r\n"+ - "\r\n"+ - "\r\n"+ - "
      \r\n"+
      -  "Some code\r\n"+
      -  "
      \r\n"+ - "
      \r\n"+ - "\r\n"+ - "Some more text." - -), // Should output - - "

      Some text:

      \n"+ - "
      \r\n"+
      -  "Some code\r\n"+
      -  "
      \n"+ - "

      Some more text.

      " - -,"notextile block"); - - -equal(textile.convert( // The textile - - "notextile.. I saw a ship. It ate my elephant.\r\n"+ - "\r\n"+ - "When the elephant comes to take a p. you..." - -), // Should output - - "I saw a ship. It ate my elephant.\r\n"+ - "\r\n"+ - "When the elephant comes to take a p. you..." - -,"extended notextile block containing block start"); - - -equal(textile.convert( // The textile - - "I am very serious.\r\n"+ - "\r\n"+ - "
      \r\n"+
      -  "  I am very serious.\r\n"+
      -  "
      " - -), // Should output - - "

      I am very serious.

      \n"+ - "
      \r\n"+
      -  "  I am <b>very</b> serious.\r\n"+
      -  "
      " - -,"html tags"); - - -equal(textile.convert( // The textile - - "I spoke.\r\n"+ - "And none replied." - -), // Should output - - "

      I spoke.
      \n"+ - "And none replied.

      " - -,"line breaks"); - - -equal(textile.convert( // The textile - - "Any old text\r\n"+ - "\r\n"+ - "bq. A block quotation.\r\n"+ - "\r\n"+ - "Any old text" - -), // Should output - - "

      Any old text

      \n"+ - "
      \n"+ - "

      A block quotation.

      \n"+ - "
      \n"+ - "

      Any old text

      " - -,"blockquote"); - - -equal(textile.convert( // The textile - - "
      \r\n"+
      -  "\r\n"+
      -  "  a.gsub!( /\r\n"+
      -  "
      " - -), // Should output - - "
      \r\n"+
      -  "\r\n"+
      -  "  a.gsub!( /</, '' )\r\n"+
      -  "\r\n"+
      -  "
      " - -,"code blocks"); - - -equal(textile.convert( // The textile - - "# A first item\r\n"+ - "# A second item\r\n"+ - "# A third" - -), // Should output - - "
        \n"+ - "\t
      1. A first item
      2. \n"+ - "\t
      3. A second item
      4. \n"+ - "\t
      5. A third
      6. \n"+ - "
      " - -,"numbered list"); - - -equal(textile.convert( // The textile - - "# Fuel could be:\r\n"+ - "## Coal\r\n"+ - "## Gasoline\r\n"+ - "## Electricity\r\n"+ - "# Humans need only:\r\n"+ - "## Water\r\n"+ - "## Protein" - -), // Should output - - "
        \n"+ - "\t
      1. Fuel could be:\n"+ - "\t
          \n"+ - "\t\t
        1. Coal
        2. \n"+ - "\t\t
        3. Gasoline
        4. \n"+ - "\t\t
        5. Electricity
        6. \n"+ - "\t
      2. \n"+ - "\t
      3. Humans need only:\n"+ - "\t
          \n"+ - "\t\t
        1. Water
        2. \n"+ - "\t\t
        3. Protein
        4. \n"+ - "\t
      4. \n"+ - "
      " - -,"nested numbered lists"); - - -equal(textile.convert( // The textile - - "* A first item\r\n"+ - "* A second item\r\n"+ - "* A third" - -), // Should output - - "
        \n"+ - "\t
      • A first item
      • \n"+ - "\t
      • A second item
      • \n"+ - "\t
      • A third
      • \n"+ - "
      " - -,"bulleted list"); - - -equal(textile.convert( // The textile - - "* Fuel could be:\r\n"+ - "** Coal\r\n"+ - "** Gasoline\r\n"+ - "** Electricity\r\n"+ - "* Humans need only:\r\n"+ - "** Water\r\n"+ - "** Protein" - -), // Should output - - "
        \n"+ - "\t
      • Fuel could be:\n"+ - "\t
          \n"+ - "\t\t
        • Coal
        • \n"+ - "\t\t
        • Gasoline
        • \n"+ - "\t\t
        • Electricity
        • \n"+ - "\t
      • \n"+ - "\t
      • Humans need only:\n"+ - "\t
          \n"+ - "\t\t
        • Water
        • \n"+ - "\t\t
        • Protein
        • \n"+ - "\t
      • \n"+ - "
      " - -,"nested bulleted lists"); - - -equal(textile.convert( // The textile - - "!>obake.gif!\r\n"+ - "\r\n"+ - "And others sat all round the small\r\n"+ - "machine and paid it to sing to them." - -), // Should output - - "

      \"\"

      \n"+ - "

      And others sat all round the small
      \n"+ - "machine and paid it to sing to them.

      " - -,"image alignments"); - - -equal(textile.convert( // The textile - - "| name | age | sex |\r\n"+ - "| joan | 24 | f |\r\n"+ - "| archie | 29 | m |\r\n"+ - "| bella | 45 | f |" - -), // Should output - - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
      name age sex
      joan 24 f
      archie 29 m
      bella 45 f
      " - -,"tables"); - - -equal(textile.convert( // HTML comment - -'line\r\n'+ -'\r\n'+ -'line' - -), // Should output - -"

      line
      \n"+ -"
      \n"+ -"line

      " - -); - - - -equal(textile.convert( - -"line\r\n"+ -"\r\n"+ -"\r\n"+ -"\r\n"+ -"line" - -), // Should output - -"

      line

      \n"+ -"\n"+ -"

      line

      " - -); - - -equal(textile.convert( // non list 3 - - "*\r\n" - -), // Should output - - "

      *

      " - -,"non list #3"); - - -equal(textile.convert( // non list 4 - - "#\r\n" - -), // Should output - - "

      #

      " - -,"non list #4"); - - -equal(textile.convert( // non list 5 - - "*\r\ntest" - -), // Should output - - "

      *
      \ntest

      " - -,"non list #5"); - - -equal(textile.convert( // empty list 1 - - "* \r\n" - -), // Should output - - "

      *

      " - -,"empty list #1"); - -equal(textile.convert( // empty list 2 - - "# \r\n" - -), // Should output - - "

      #

      " - -,"empty list #2"); - -equal(textile.convert( // insert empty list 1 - - "*\r\n\r\ntest" - -), // Should output - - "

      *

      \n

      test

      " - -,"insert empty list #1"); - -equal(textile.convert( // insert empty list 2 - - "#\r\n\r\ntest" - -), // Should output - - "

      #

      \n

      test

      " - -,"insert empty list #2"); - - -equal(textile.convert( // strict list matching (1) - - '*{color:red} item*\r\n\r\n'+ - '* item*\r\n\r\n'+ - '*item*' - -), // Should output - - '
        \n'+ - '\t
      • item*
      • \n'+ - '
      \n'+ - '
        \n'+ - '\t
      • item*
      • \n'+ - '
      \n'+ - '

      item

      ' - -,"strict list matching (1)"); - -equal(textile.convert( // strict list matching (2) - - '*{color:red} item\r\n\r\n'+ - '* item\r\n\r\n'+ - '*item' - -), // Should output - - '
        \n'+ - '\t
      • item
      • \n'+ - '
      \n'+ - '
        \n'+ - '\t
      • item
      • \n'+ - '
      \n'+ - '

      *item

      ' - -,"strict list matching (2)"); - - - - - - - - -// greedy globbing block parser bug [#21] - -equal(textile.convert( // The textile - - "pab\r\n\r\n"+ - "pabcde\r\n\r\n"+ - "bqabcdef\r\n\r\n"+ - "last line ending in period+space. \r\n" - -), // Should output - - '

      pab

      \n'+ - '

      pabcde

      \n'+ - '

      bqabcdef

      \n'+ - '

      last line ending in period+space.

      ' - -,"block parser bug (#21)"); - - - +// jstextile linebreaks +import test from 'ava'; +import textile from '../src'; + +test( 'paragraphs', function ( t ) { + let tx = "A single paragraph.\r\n\r\n\ +Followed by another."; + t.is( textile.convert( tx ), + "

      A single paragraph.

      \n\ +

      Followed by another.

      ", tx ); +}); -equal(textile.convert( // The textile +test( 'blocks with spaces on the blank line in between', function ( t ) { + let tx = "This is line one\r\n\ + \r\n\ +This is line two"; + t.is( textile.convert( tx ), + "

      This is line one

      \n\ +

      This is line two

      ", tx ); +}); - "h1. Header\r\n"+ - "\r\n"+ - "text" -), // Should output +test( 'blocks with tabl on the blank line in between', function ( t ) { + let tx = "This is line one\r\n\ +\t\r\n\ +This is line two"; + t.is( textile.convert( tx ), + "

      This is line one

      \n\ +

      This is line two

      ", tx ); +}); - "

      Header

      \n"+ - "

      text

      " -,"header with 1 blank line below"); +test( 'extended blockquote containing block start', function ( t ) { + let tx = "bq.. I saw a ship. It ate my elephant.\r\n\r\n\ +When the elephant comes to take a p. you..."; + t.is( textile.convert( tx ), + "
      \n\ +

      I saw a ship. It ate my elephant.

      \n\ +

      When the elephant comes to take a p. you…

      \n\ +
      ", tx ); +}); -equal(textile.convert( // The textile +test( 'notextile block', function ( t ) { + let tx = "Some text:\r\n\r\n\ +\r\n\ +
      \r\n\
      +Some code\r\n\
      +
      \r\n\ +
      \r\n\r\n\ +Some more text."; + t.is( textile.convert( tx ), + "

      Some text:

      \n\ +
      \r\n\
      +Some code\r\n\
      +
      \n\ +

      Some more text.

      ", tx ); +}); - "h1. Header\r\n"+ - "\r\n"+ - "\r\n"+ - "text" -), // Should output +test( 'extended notextile block containing block start', function ( t ) { + let tx = "notextile.. I saw a ship. It ate my elephant.\r\n\r\n\ +When the elephant comes to take a p. you..."; + t.is( textile.convert( tx ), + "I saw a ship. It ate my elephant.\r\n\r\n\ +When the elephant comes to take a p. you...", tx ); +}); - "

      Header

      \n"+ - "

      text

      " -,"header with 2 blank lines below"); +test( 'html tags', function ( t ) { + let tx = "I am very serious.\r\n\r\n\ +
      \r\n\
      +  I am very serious.\r\n\
      +
      "; + t.is( textile.convert( tx ), + "

      I am very serious.

      \n\ +
      \r\n\
      +  I am <b>very</b> serious.\r\n\
      +
      ", tx ); +}); -equal(textile.convert( // The textile +test( 'line breaks', function ( t ) { + let tx = "I spoke.\r\n\ +And none replied."; + t.is( textile.convert( tx ), + "

      I spoke.
      \n\ +And none replied.

      ", tx ); +}); - "text\r\n"+ - "\r\n"+ - "h1. Header" -), // Should output +test( 'blockquote', function ( t ) { + let tx = "Any old text\r\n\r\n\ +bq. A block quotation.\r\n\r\n\ +Any old text"; + t.is( textile.convert( tx ), + "

      Any old text

      \n\ +
      \n\ +

      A block quotation.

      \n\ +
      \n\ +

      Any old text

      ", tx ); +}); - "

      text

      \n"+ - "

      Header

      " -,"header with 1 blank line above"); +test( 'code blocks', function ( t ) { + let tx = "
      \r\n\
      +\r\n\
      +  a.gsub!( /\r\n\
      +
      "; + t.is( textile.convert( tx ), + "
      \r\n\
      +\r\n\
      +  a.gsub!( /</, '' )\r\n\
      +\r\n\
      +
      ", tx ); +}); -equal(textile.convert( // The textile +test( 'numbered list', function ( t ) { + let tx = "# A first item\r\n\ +# A second item\r\n\ +# A third"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. A first item
      2. \n\ +\t
      3. A second item
      4. \n\ +\t
      5. A third
      6. \n\ +
      ", tx ); +}); - "text\r\n"+ - "\r\n"+ - "\r\n"+ - "h1. Header" -), // Should output +test( 'nested numbered lists', function ( t ) { + let tx = "# Fuel could be:\r\n\ +## Coal\r\n\ +## Gasoline\r\n\ +## Electricity\r\n\ +# Humans need only:\r\n\ +## Water\r\n\ +## Protein"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. Fuel could be:\n\ +\t
          \n\ +\t\t
        1. Coal
        2. \n\ +\t\t
        3. Gasoline
        4. \n\ +\t\t
        5. Electricity
        6. \n\ +\t
      2. \n\ +\t
      3. Humans need only:\n\ +\t
          \n\ +\t\t
        1. Water
        2. \n\ +\t\t
        3. Protein
        4. \n\ +\t
      4. \n\ +
      ", tx ); +}); - "

      text

      \n"+ - "

      Header

      " -,"header with 2 blank lines above"); +test( 'bulleted list', function ( t ) { + let tx = "* A first item\r\n\ +* A second item\r\n\ +* A third"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      • A first item
      • \n\ +\t
      • A second item
      • \n\ +\t
      • A third
      • \n\ +
      ", tx ); +}); +test( 'nested bulleted lists', function ( t ) { + let tx = "* Fuel could be:\r\n\ +** Coal\r\n\ +** Gasoline\r\n\ +** Electricity\r\n\ +* Humans need only:\r\n\ +** Water\r\n\ +** Protein"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      • Fuel could be:\n\ +\t
          \n\ +\t\t
        • Coal
        • \n\ +\t\t
        • Gasoline
        • \n\ +\t\t
        • Electricity
        • \n\ +\t
      • \n\ +\t
      • Humans need only:\n\ +\t
          \n\ +\t\t
        • Water
        • \n\ +\t\t
        • Protein
        • \n\ +\t
      • \n\ +
      ", tx ); +}); +test( 'image alignments', function ( t ) { + let tx = "!>obake.gif!\r\n\r\n\ +And others sat all round the small\r\n\ +machine and paid it to sing to them."; + t.is( textile.convert( tx ), + "

      \"\"

      \n\ +

      And others sat all round the small
      \n\ +machine and paid it to sing to them.

      ", tx ); +}); +test( 'tables', function ( t ) { + let tx = "| name | age | sex |\r\n\ +| joan | 24 | f |\r\n\ +| archie | 29 | m |\r\n\ +| bella | 45 | f |"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
      name age sex
      joan 24 f
      archie 29 m
      bella 45 f
      ", tx ); +}); -equal(textile.convert( // The textile - "* 1\n"+ - "* 2\n"+ - "* 3\n" +test( 'jstextile linebreaks:17', function ( t ) { + let tx = "line\r\n\ +\r\n\ +line"; + t.is( textile.convert( tx ), + "

      line
      \n\ +
      \n\ +line

      ", tx ); +}); -), // Should output - "
        \n"+ - "\t
      • 1
      • \n"+ - "\t
      • 2
      • \n"+ - "\t
      • 3
      • \n"+ - "
      " +test( 'jstextile linebreaks:18', function ( t ) { + let tx = "line\r\n\r\n\ +\r\n\r\n\ +line"; + t.is( textile.convert( tx ), + "

      line

      \n\ +\n\ +

      line

      ", tx ); +}); -,"list line break bug 1"); -equal(textile.convert( // The textile +test( 'non list #3', function ( t ) { + let tx = "*\r\n\ +"; + t.is( textile.convert( tx ), + "

      *

      ", tx ); +}); - "* 1\r\n"+ - "* 2\r\n"+ - "* 3\r\n" -), // Should output +test( 'non list #4', function ( t ) { + let tx = "#\r\n\ +"; + t.is( textile.convert( tx ), + "

      #

      ", tx ); +}); - "
        \n"+ - "\t
      • 1
      • \n"+ - "\t
      • 2
      • \n"+ - "\t
      • 3
      • \n"+ - "
      " -,"list line break bug 2"); +test( 'non list #5', function ( t ) { + let tx = "*\r\n\ +test"; + t.is( textile.convert( tx ), + "

      *
      \n\ +test

      ", tx ); +}); +test( 'empty list #1', function ( t ) { + let tx = "* \r\n\ +"; + t.is( textile.convert( tx ), + "

      *

      ", tx ); +}); +test( 'empty list #2', function ( t ) { + let tx = "# \r\n\ +"; + t.is( textile.convert( tx ), + "

      #

      ", tx ); +}); -// definitions -equal(textile.convert( // The textile +test( 'insert empty list #1', function ( t ) { + let tx = "*\r\n\r\n\ +test"; + t.is( textile.convert( tx ), + "

      *

      \n\ +

      test

      ", tx ); +}); - "- term := you can have line breaks\r\n"+ - "just like other lists\r\n"+ - "- line-spanning\r\n"+ - "term := hey, slick!" -), // Should output +test( 'insert empty list #2', function ( t ) { + let tx = "#\r\n\r\n\ +test"; + t.is( textile.convert( tx ), + "

      #

      \n\ +

      test

      ", tx ); +}); - "
      \n"+ - "\t
      term
      \n"+ - "\t
      you can have line breaks
      \n"+ - "just like other lists
      \n"+ - "\t
      line-spanning
      \n"+ - "term
      \n"+ - "\t
      hey, slick!
      \n"+ - "
      " -,"with line breaks"); +test( 'strict list matching (1)', function ( t ) { + let tx = "*{color:red} item*\r\n\r\n\ +* item*\r\n\r\n\ +*item*"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      • item*
      • \n\ +
      \n\ +
        \n\ +\t
      • item*
      • \n\ +
      \n\ +

      item

      ", tx ); +}); -equal(textile.convert( // The textile +test( 'strict list matching (2)', function ( t ) { + let tx = "*{color:red} item\r\n\r\n\ +* item\r\n\r\n\ +*item"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      • item
      • \n\ +
      \n\ +
        \n\ +\t
      • item
      • \n\ +
      \n\ +

      *item

      ", tx ); +}); - "You can have multiple terms before a definition:\r\n"+ - "\r\n"+ - "- textile\r\n"+ - "- fabric\r\n"+ - "- cloth := woven threads" -), // Should output +test( 'block parser bug (#21)', function ( t ) { + let tx = "pab\r\n\r\n\ +pabcde\r\n\r\n\ +bqabcdef\r\n\r\n\ +last line ending in period+space. \r\n\ +"; + t.is( textile.convert( tx ), + "

      pab

      \n\ +

      pabcde

      \n\ +

      bqabcdef

      \n\ +

      last line ending in period+space.

      ", tx ); +}); - "

      You can have multiple terms before a definition:

      \n"+ - "
      \n"+ - "\t
      textile
      \n"+ - "\t
      fabric
      \n"+ - "\t
      cloth
      \n"+ - "\t
      woven threads
      \n"+ - "
      " -,"double terms"); +test( 'header with 1 blank line below', function ( t ) { + let tx = "h1. Header\r\n\r\n\ +text"; + t.is( textile.convert( tx ), + "

      Header

      \n\ +

      text

      ", tx ); +}); -equal(textile.convert( // The textile +test( 'header with 2 blank lines below', function ( t ) { + let tx = "h1. Header\r\n\r\n\r\n\ +text"; + t.is( textile.convert( tx ), + "

      Header

      \n\ +

      text

      ", tx ); +}); - "- textile\r\n"+ - "- fabric\r\n"+ - "- cloth" -), // Should output +test( 'header with 1 blank line above', function ( t ) { + let tx = "text\r\n\r\n\ +h1. Header"; + t.is( textile.convert( tx ), + "

      text

      \n\ +

      Header

      ", tx ); +}); - "

      - textile
      \n"+ - "- fabric
      \n"+ - "- cloth

      " -,"not a definition list"); +test( 'header with 2 blank lines above', function ( t ) { + let tx = "text\r\n\r\n\r\n\ +h1. Header"; + t.is( textile.convert( tx ), + "

      text

      \n\ +

      Header

      ", tx ); +}); -equal(textile.convert( // The textile +test( 'list line break bug 1', function ( t ) { + let tx = "* 1\n\ +* 2\n\ +* 3\n\ +"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      • 1
      • \n\ +\t
      • 2
      • \n\ +\t
      • 3
      • \n\ +
      ", tx ); +}); - "here is a long definition\r\n"+ - "\r\n"+ - "- some term := \r\n"+ - "*sweet*\r\n"+ - "\r\n"+ - "yes\r\n"+ - "\r\n"+ - "ok =:\r\n"+ - "- regular term := no" -), // Should output +test( 'list line break bug 2', function ( t ) { + let tx = "* 1\r\n\ +* 2\r\n\ +* 3\r\n\ +"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      • 1
      • \n\ +\t
      • 2
      • \n\ +\t
      • 3
      • \n\ +
      ", tx ); +}); - "

      here is a long definition

      \n"+ - "
      \n"+ - "\t
      some term
      \n"+ - "\t

      sweet

      \n"+ - "

      yes

      \n"+ - "

      ok

      \n"+ - "\t
      regular term
      \n"+ - "\t
      no
      \n"+ - "
      " -,"long definition list"); +test( 'with line breaks', function ( t ) { + let tx = "- term := you can have line breaks\r\n\ +just like other lists\r\n\ +- line-spanning\r\n\ +term := hey, slick!"; + t.is( textile.convert( tx ), + "
      \n\ +\t
      term
      \n\ +\t
      you can have line breaks
      \n\ +just like other lists
      \n\ +\t
      line-spanning
      \n\ +term
      \n\ +\t
      hey, slick!
      \n\ +
      ", tx ); +}); +test( 'double terms', function ( t ) { + let tx = "You can have multiple terms before a definition:\r\n\r\n\ +- textile\r\n\ +- fabric\r\n\ +- cloth := woven threads"; + t.is( textile.convert( tx ), + "

      You can have multiple terms before a definition:

      \n\ +
      \n\ +\t
      textile
      \n\ +\t
      fabric
      \n\ +\t
      cloth
      \n\ +\t
      woven threads
      \n\ +
      ", tx ); +}); +test( 'not a definition list', function ( t ) { + let tx = "- textile\r\n\ +- fabric\r\n\ +- cloth"; + t.is( textile.convert( tx ), + "

      - textile
      \n\ +- fabric
      \n\ +- cloth

      ", tx ); +}); +test( 'long definition list', function ( t ) { + let tx = "here is a long definition\r\n\r\n\ +- some term := \r\n\ +*sweet*\r\n\r\n\ +yes\r\n\r\n\ +ok =:\r\n\ +- regular term := no"; + t.is( textile.convert( tx ), + "

      here is a long definition

      \n\ +
      \n\ +\t
      some term
      \n\ +\t

      sweet

      \n\ +

      yes

      \n\ +

      ok

      \n\ +\t
      regular term
      \n\ +\t
      no
      \n\ +
      ", tx ); }); + diff --git a/test/links.js b/test/links.js new file mode 100644 index 0000000..8427d66 --- /dev/null +++ b/test/links.js @@ -0,0 +1,563 @@ +// links.yml +import test from 'ava'; +import textile from '../src'; + +test( 'links:1', function ( t ) { + let tx = "\"link text\":#1"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:2', function ( t ) { + let tx = "\"link text\":#a"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:3', function ( t ) { + let tx = "\"link text\":#a1"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:4', function ( t ) { + let tx = "\"link text\":#a10"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:5', function ( t ) { + let tx = "\"link text\":index.html"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:6', function ( t ) { + let tx = "\"link text\":index.html#1"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:7', function ( t ) { + let tx = "\"link text\":index.html#a"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:8', function ( t ) { + let tx = "\"link text\":index.html#a1"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:9', function ( t ) { + let tx = "\"link text\":index.html#a10"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:10', function ( t ) { + let tx = "\"link text\":http://example.com/"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:11', function ( t ) { + let tx = "\"link text\":http://example.com/#1"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:12', function ( t ) { + let tx = "\"link text\":http://example.com/#a"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:13', function ( t ) { + let tx = "\"link text\":http://example.com/#a1"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:14', function ( t ) { + let tx = "\"link text\":http://example.com/#a10"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:15', function ( t ) { + let tx = "\"link text\":http://example.com/index.html"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:16', function ( t ) { + let tx = "\"link text\":http://example.com/index.html#a"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:17', function ( t ) { + let tx = "\"link text\":http://example.com/index.html#1"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:18', function ( t ) { + let tx = "\"link text\":http://example.com/index.html#a1"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:19', function ( t ) { + let tx = "\"link text\":http://example.com/index.html#a10"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:20', function ( t ) { + let tx = "\"link text\":http://example.com/?foo=bar"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:21', function ( t ) { + let tx = "\"link text\":http://example.com/?foo=bar#a"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:22', function ( t ) { + let tx = "\"link & text\":http://example.com/?foo=bar#a"; + t.is( textile.convert( tx ), + "

      link & text

      ", tx ); +}); + + +test( 'links:23', function ( t ) { + let tx = "\"link text\":http://example.com/?foo=bar#1"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:24', function ( t ) { + let tx = "\"link text\":http://example.com/?foo=bar#a1"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:25', function ( t ) { + let tx = "\"link text\":http://example.com/?foo=bar#a10"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:26', function ( t ) { + let tx = "\"link text\":http://example.com/?foo=bar&a=b"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:27', function ( t ) { + let tx = "\"link text\":http://example.com/?foo=bar&a=b#1"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:28', function ( t ) { + let tx = "\"link text\":http://example.com/?foo=bar&a=b#a"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:29', function ( t ) { + let tx = "\"link text\":http://example.com/?foo=bar&a=b#a1"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:30', function ( t ) { + let tx = "\"link text\":http://example.com/?foo=bar&a=b#a10"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'links:31', function ( t ) { + let tx = "This is a \"link\":http://example.com/"; + t.is( textile.convert( tx ), + "

      This is a link

      ", tx ); +}); + + +test( 'links:32', function ( t ) { + let tx = "This is a \"link\":http://example.com/."; + t.is( textile.convert( tx ), + "

      This is a link.

      ", tx ); +}); + + +test( 'links:33', function ( t ) { + let tx = "This is a \"link\":http://example.com/index.html."; + t.is( textile.convert( tx ), + "

      This is a link.

      ", tx ); +}); + + +test( 'links:34', function ( t ) { + let tx = "This is a \"link\":http://example.com/index.html#a."; + t.is( textile.convert( tx ), + "

      This is a link.

      ", tx ); +}); + + +test( 'links:35', function ( t ) { + let tx = "This is a \"link\":http://example.com/index.html#1."; + t.is( textile.convert( tx ), + "

      This is a link.

      ", tx ); +}); + + +test( 'links:36', function ( t ) { + let tx = "This is a \"link\":http://example.com/index.html#a1."; + t.is( textile.convert( tx ), + "

      This is a link.

      ", tx ); +}); + + +test( 'links:37', function ( t ) { + let tx = "This is a \"link\":http://example.com/index.html#a10."; + t.is( textile.convert( tx ), + "

      This is a link.

      ", tx ); +}); + + +test( 'links:38', function ( t ) { + let tx = "This is a \"link\":http://example.com/?foo=bar."; + t.is( textile.convert( tx ), + "

      This is a link.

      ", tx ); +}); + + +test( 'links:39', function ( t ) { + let tx = "This is a \"link\":http://example.com/?foo=bar#1."; + t.is( textile.convert( tx ), + "

      This is a link.

      ", tx ); +}); + + +test( 'links:40', function ( t ) { + let tx = "This is a \"link\":http://example.com/?foo=bar#a."; + t.is( textile.convert( tx ), + "

      This is a link.

      ", tx ); +}); + + +test( 'links:41', function ( t ) { + let tx = "This is a \"link\":http://example.com/?foo=bar#a1."; + t.is( textile.convert( tx ), + "

      This is a link.

      ", tx ); +}); + + +test( 'links:42', function ( t ) { + let tx = "This is a \"link\":http://example.com/?foo=bar#a10."; + t.is( textile.convert( tx ), + "

      This is a link.

      ", tx ); +}); + + +test( 'links:43', function ( t ) { + let tx = "This is a \"link\":http://example.com/?foo=bar#a10, but this is not."; + t.is( textile.convert( tx ), + "

      This is a link, but this is not.

      ", tx ); +}); + + +test( 'links:44', function ( t ) { + let tx = "(This is a \"link\":http://example.com/?foo=bar#a10) but this is not."; + t.is( textile.convert( tx ), + "

      (This is a link) but this is not.

      ", tx ); +}); + + +test( 'links:45', function ( t ) { + let tx = "\"link text(link title)\":http://example.com/"; + t.is( textile.convert( tx ), + "

      link text

      ", tx ); +}); + + +test( 'link with title attribute', function ( t ) { + let tx = "\"(link) text(link title)\":http://example.com/"; + t.is( textile.convert( tx ), + "

      text

      ", tx ); +}); + + +test( 'link with space between link text and title attribute', function ( t ) { + let tx = "\"text (link title)\":http://example.com/"; + t.is( textile.convert( tx ), + "

      text

      ", tx ); +}); + + +test( 'links:48', function ( t ) { + let tx = "\"Dive Into XML\":http://www.xml.com/pub/au/164"; + t.is( textile.convert( tx ), + "

      Dive Into XML

      ", tx ); +}); + + +test( 'links:49', function ( t ) { + let tx = "\"Lab Exercises\":../lab/exercises/exercises.html."; + t.is( textile.convert( tx ), + "

      Lab Exercises.

      ", tx ); +}); + + +test( 'links:50', function ( t ) { + let tx = "Go to \"discuss\":http://www.dreammoods.com/cgibin/cutecast/cutecast.pl?forum=1&thread=26627 to discuss."; + t.is( textile.convert( tx ), + "

      Go to discuss to discuss.

      ", tx ); +}); + + +test( 'links:51', function ( t ) { + let tx = "* \"rubylang\":http://www.ruby-lang.org/en/"; + t.is( textile.convert( tx ), + "", tx ); +}); + + +test( 'links:52', function ( t ) { + let tx = "The ION coding style document found at \"IONCodingStyleGuide.doc\":http://perforce:8081/@md=d&cd=//&c=82E@//depot/systest/system/main/pub/doc/IONCodingStyleGuide.doc?ac=22 codifies a couple of rules to ensure reasonably consistent code and documentation of libraries in ION. Test text"; + t.is( textile.convert( tx ), + "

      The ION coding style document found at IONCodingStyleGuide.doc codifies a couple of rules to ensure reasonably consistent code and documentation of libraries in ION. Test text

      ", tx ); +}); + + +test( 'links:53', function ( t ) { + let tx = "\"testing\":"; + t.is( textile.convert( tx ), + "

      “testing”:

      ", tx ); +}); + + +test( 'trailing space not absorbed by link', function ( t ) { + let tx = "\"Link\":/foo.html me"; + t.is( textile.convert( tx ), + "

      Link me

      ", tx ); +}); + + +test( 'trailing comma stays outside link', function ( t ) { + let tx = "\"Link\":/foo.html, me"; + t.is( textile.convert( tx ), + "

      Link, me

      ", tx ); +}); + + +test( 'trailing exclamation stays outside link', function ( t ) { + let tx = "\"Link\":/foo.html! me"; + t.is( textile.convert( tx ), + "

      Link! me

      ", tx ); +}); + + +test( 'trailing semicolon stays outside link', function ( t ) { + let tx = "\"Link\":/foo.html; me"; + t.is( textile.convert( tx ), + "

      Link; me

      ", tx ); +}); + + +test( 'trailing period stays outside link', function ( t ) { + let tx = "\"Link\":/foo.html."; + t.is( textile.convert( tx ), + "

      Link.

      ", tx ); +}); + + +test( 'whose text is a parenthetical statement', function ( t ) { + let tx = "\"(just in case you were wondering)\":http://slashdot.org/"; + t.is( textile.convert( tx ), + "

      (just in case you were wondering)

      ", tx ); +}); + + +test( 'that has a class and whose text is a parenthetical statement', function ( t ) { + let tx = "\"(myclass) (just in case you were wondering)\":http://slashdot.org/"; + t.is( textile.convert( tx ), + "

      (just in case you were wondering)

      ", tx ); +}); + + +test( 'link containing parentheses', function ( t ) { + let tx = "\"It is (very) fortunate that this works\":http://slashdot.org/"; + t.is( textile.convert( tx ), + "

      It is (very) fortunate that this works

      ", tx ); +}); + + +test( 'link containing quotes', function ( t ) { + let tx = "\"He said it is \"very unlikely\" this works\":http://slashdot.org/"; + t.is( textile.convert( tx ), + "

      He said it is “very unlikely” this works

      ", tx ); +}); + + +test( 'link containing multiple quotes', function ( t ) { + let tx = "\"He said it is \"very unlikely\" the \"economic stimulus\" works\":http://slashdot.org/"; + t.is( textile.convert( tx ), + "

      He said it is “very unlikely” the “economic stimulus” works

      ", tx ); +}); + + +test( 'linked quoted phrase', function ( t ) { + let tx = "\"\"Open the pod bay doors please, HAL.\"\":http://www.youtube.com/watch?v=npN9l2Bd06s"; + t.is( textile.convert( tx ), + "

      “Open the pod bay doors please, HAL.”

      ", tx ); +}); + + +test( 'link following quoted phrase', function ( t ) { + let tx = "\"quote\" text \"quote\" text \"link\":http://google.com"; + t.is( textile.convert( tx ), + "

      “quote” text “quote” text link

      ", tx ); +}); + + +test( 'links containing underscores', function ( t ) { + let tx = "This is a link to a \"Wikipedia article about Barack\":http://en.wikipedia.org/wiki/Barack_Obama"; + t.is( textile.convert( tx ), + "

      This is a link to a Wikipedia article about Barack

      ", tx ); +}); + + +test( 'links containing parentheses', function ( t ) { + let tx = "This is a link to a [\"Wikipedia article about Textile\":http://en.wikipedia.org/wiki/Textile_(markup_language)]"; + t.is( textile.convert( tx ), + "

      This is a link to a Wikipedia article about Textile

      ", tx ); +}); + + +test( 'links contained in parentheses', function ( t ) { + let tx = "This is a regular link (but in parentheses: \"Google\":http://www.google.com)"; + t.is( textile.convert( tx ), + "

      This is a regular link (but in parentheses: Google)

      ", tx ); +}); + + +test( 'links containing parentheses without brackets', function ( t ) { + let tx = "This is a link to a \"Wikipedia article about Textile\":http://en.wikipedia.org/wiki/Textile_(markup_language)"; + t.is( textile.convert( tx ), + "

      This is a link to a Wikipedia article about Textile

      ", tx ); +}); + + +test( 'links containing parentheses period at end without brackets', function ( t ) { + let tx = "This is a link to a \"Wikipedia article about Textile\":http://en.wikipedia.org/wiki/Textile_(markup_language)."; + t.is( textile.convert( tx ), + "

      This is a link to a Wikipedia article about Textile.

      ", tx ); +}); + + +test( 'broken links containing parentheses without brackets', function ( t ) { + let tx = "This is a link to a \"Wikipedia article about Textile\":http://en.wikipedia.org/wiki/Textile_(markup_language"; + t.is( textile.convert( tx ), + "

      This is a link to a Wikipedia article about Textile

      ", tx ); +}); + + +test( 'links containing parentheses without brackets inside a parenthesis', function ( t ) { + let tx = "Textile is awesome! (Check out the \"Wikipedia article about Textile\":http://en.wikipedia.org/wiki/Textile_(markup_language))"; + t.is( textile.convert( tx ), + "

      Textile is awesome! (Check out the Wikipedia article about Textile)

      ", tx ); +}); + + +test( 'quotes and follow link', function ( t ) { + let tx = "Some \"text\" followed by a \"link\":http://redcloth.org."; + t.is( textile.convert( tx ), + "

      Some “text” followed by a link.

      ", tx ); +}); + + +test( 'link alias containing dashes', function ( t ) { + let tx = "\"link\":google-rocks\n\n\ +[google-rocks]http://google.com"; + t.is( textile.convert( tx ), + "

      link

      ", tx ); +}); + + +test( 'contained in multi-paragraph quotes', function ( t ) { + let tx = "\"I first learned about \"Redcloth\":http://redcloth.org/ several years ago.\n\n\ +\"It's wonderful.\""; + t.is( textile.convert( tx ), + "

      “I first learned about Redcloth several years ago.

      \n\ +

      “It’s wonderful.”

      ", tx ); +}); + + +test( 'as html in notextile contained in multi-paragraph quotes', function ( t ) { + let tx = "\"Here is a link.\n\n\ +\"I like links.\""; + t.is( textile.convert( tx ), + "

      “Here is a link.

      \n\ +

      “I like links.”

      ", tx ); +}); + + +test( 'contained in para with multiple quotes', function ( t ) { + let tx = "\"My wife, Tipper, and I will donate 100% of the proceeds of the award to the \"Alliance For Climate Protection\":http://www.looktothestars.org/charity/638-alliance-for-climate-protection,\" said Gore in an email. \"I am deeply honored to receive the Nobel Peace Prize.\""; + t.is( textile.convert( tx ), + "

      “My wife, Tipper, and I will donate 100% of the proceeds of the award to the Alliance For Climate Protection,” said Gore in an email. “I am deeply honored to receive the Nobel Peace Prize.”

      ", tx ); +}); + + +test( 'with caps in the title', function ( t ) { + let tx = "\"British Skin Foundation (BSF)\":http://www.britishskinfoundation.org.uk"; + t.is( textile.convert( tx ), + "

      British Skin Foundation

      ", tx ); +}); + + +test( 'containing HTML tags with quotes', function ( t ) { + let tx = "\"\"Apply*apply online*\":/admissions/apply/"; + t.is( textile.convert( tx ), + "

      \"Applyapply online

      ", tx ); +}); + diff --git a/test/lists.js b/test/lists.js new file mode 100644 index 0000000..654de11 --- /dev/null +++ b/test/lists.js @@ -0,0 +1,493 @@ +// lists.yml +import test from 'ava'; +import textile from '../src'; + +test( 'code in bullet list', function ( t ) { + let tx = "* command run: @time ruby run-tests.rb > toto@"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      • command run: time ruby run-tests.rb > toto
      • \n\ +
      ", tx ); +}); + + +test( 'hard break in list', function ( t ) { + let tx = "* first line\n\ +* second\n\ + line\n\ +* third line"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      • first line
      • \n\ +\t
      • second
        \n\ +line
      • \n\ +\t
      • third line
      • \n\ +
      ", tx ); +}); + + +test( 'mixed nesting', function ( t ) { + let tx = "* bullet\n\ +*# number\n\ +*# number\n\ +*#* bullet\n\ +*# number\n\ +*# number with\n\ +a break\n\ +* bullet\n\ +** okay"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      • bullet\n\ +\t
          \n\ +\t\t
        1. number
        2. \n\ +\t\t
        3. number\n\ +\t\t
            \n\ +\t\t\t
          • bullet
          • \n\ +\t\t
        4. \n\ +\t\t
        5. number
        6. \n\ +\t\t
        7. number with
          \n\ +a break
        8. \n\ +\t
      • \n\ +\t
      • bullet\n\ +\t
          \n\ +\t\t
        • okay
        • \n\ +\t
      • \n\ +
      ", tx ); +}); + + +test( 'list continuation', function ( t ) { + let tx = "# one\n\ +# two\n\ +# three\n\n\ +# one\n\ +# two\n\ +# three\n\n\ +#_ four\n\ +# five\n\ +# six"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. one
      2. \n\ +\t
      3. two
      4. \n\ +\t
      5. three
      6. \n\ +
      \n\ +
        \n\ +\t
      1. one
      2. \n\ +\t
      3. two
      4. \n\ +\t
      5. three
      6. \n\ +
      \n\ +
        \n\ +\t
      1. four
      2. \n\ +\t
      3. five
      4. \n\ +\t
      5. six
      6. \n\ +
      ", tx ); +}); + + +test( 'continue after break', function ( t ) { + let tx = "# one\n\ +# two\n\ +# three\n\n\ +test\n\n\ +#_ four\n\ +# five\n\ +# six\n\n\ +test\n\n\ +#_ seven\n\ +# eight\n\ +# nine"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. one
      2. \n\ +\t
      3. two
      4. \n\ +\t
      5. three
      6. \n\ +
      \n\ +

      test

      \n\ +
        \n\ +\t
      1. four
      2. \n\ +\t
      3. five
      4. \n\ +\t
      5. six
      6. \n\ +
      \n\ +

      test

      \n\ +
        \n\ +\t
      1. seven
      2. \n\ +\t
      3. eight
      4. \n\ +\t
      5. nine
      6. \n\ +
      ", tx ); +}); + + +test( 'continue list when prior list contained nested list', function ( t ) { + let tx = "# one\n\ +# two\n\ +# three\n\n\ +#_ four\n\ +# five\n\ +## sub-note\n\ +## another sub-note\n\ +# six\n\n\ +#_ seven\n\ +# eight\n\ +# nine"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. one
      2. \n\ +\t
      3. two
      4. \n\ +\t
      5. three
      6. \n\ +
      \n\ +
        \n\ +\t
      1. four
      2. \n\ +\t
      3. five\n\ +\t
          \n\ +\t\t
        1. sub-note
        2. \n\ +\t\t
        3. another sub-note
        4. \n\ +\t
      4. \n\ +\t
      5. six
      6. \n\ +
      \n\ +
        \n\ +\t
      1. seven
      2. \n\ +\t
      3. eight
      4. \n\ +\t
      5. nine
      6. \n\ +
      ", tx ); +}); + + +test( 'list start number', function ( t ) { + let tx = "#293 two ninety three\n\ +# two ninety four\n\ +# two ninety five\n\n\ +#9 nine\n\ +# ten\n\ +# eleven"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. two ninety three
      2. \n\ +\t
      3. two ninety four
      4. \n\ +\t
      5. two ninety five
      6. \n\ +
      \n\ +
        \n\ +\t
      1. nine
      2. \n\ +\t
      3. ten
      4. \n\ +\t
      5. eleven
      6. \n\ +
      ", tx ); +}); + + +test( 'continue list after started list', function ( t ) { + let tx = "#9 nine\n\ +# ten\n\ +# eleven\n\n\ +#_ twelve\n\ +# thirteen\n\ +# fourteen"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. nine
      2. \n\ +\t
      3. ten
      4. \n\ +\t
      5. eleven
      6. \n\ +
      \n\ +
        \n\ +\t
      1. twelve
      2. \n\ +\t
      3. thirteen
      4. \n\ +\t
      5. fourteen
      6. \n\ +
      ", tx ); +}); + + +test( 'end notes', function ( t ) { + let tx = "h2. End Notes\n\n\ +# End Notes should be a numbered list\n\ +# Like this\n\ +# They must have anchors in the text\n\n\ +h2. See Also\n\n\ +* See Also notes should be bullets\n\ +* Like this\n\ +"; + t.is( textile.convert( tx ), + "

      End Notes

      \n\ +
        \n\ +\t
      1. End Notes should be a numbered list
      2. \n\ +\t
      3. Like this
      4. \n\ +\t
      5. They must have anchors in the text
      6. \n\ +
      \n\ +

      See Also

      \n\ +
        \n\ +\t
      • See Also notes should be bullets
      • \n\ +\t
      • Like this
      • \n\ +
      ", tx ); +}); + + +test( 'ordered list immediately following paragraph', function ( t ) { + let tx = "A simple example.\n\ +# One\n\ +# Two"; + t.is( textile.convert( tx ), + "

      A simple example.

      \n\ +
        \n\ +\t
      1. One
      2. \n\ +\t
      3. Two
      4. \n\ +
      ", tx ); +}); + + +test( 'unordered list immediately following paragraph', function ( t ) { + let tx = "A simple example.\n\ +* One\n\ +* Two"; + t.is( textile.convert( tx ), + "

      A simple example.

      \n\ +
        \n\ +\t
      • One
      • \n\ +\t
      • Two
      • \n\ +
      ", tx ); +}); + + +test( 'ordered list immediately following extended block', function ( t ) { + let tx = "div.. Here it comes.\n\n\ +A simple example.\n\ +# One\n\ +# Two"; + t.is( textile.convert( tx ), + "
      Here it comes.
      \n\ +
      A simple example.
      \n\ +
        \n\ +\t
      1. One
      2. \n\ +\t
      3. Two
      4. \n\ +
      ", tx ); +}); + + +test( 'unordered list immediately following extended block', function ( t ) { + let tx = "div.. Here it comes.\n\n\ +A simple example.\n\ +* One\n\ +* Two"; + t.is( textile.convert( tx ), + "
      Here it comes.
      \n\ +
      A simple example.
      \n\ +
        \n\ +\t
      • One
      • \n\ +\t
      • Two
      • \n\ +
      ", tx ); +}); + + +test( 'unordered with classes', function ( t ) { + let tx = "*(class-one) one\n\ +*(class-two) two\n\ +*(class-three) three"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      • one
      • \n\ +\t
      • two
      • \n\ +\t
      • three
      • \n\ +
      ", tx ); +}); + + +test( 'unordered with alignments', function ( t ) { + let tx = "*< one\n\ +*> two\n\ +*<> three\n\ +*= four"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      • one
      • \n\ +\t
      • two
      • \n\ +\t
      • three
      • \n\ +\t
      • four
      • \n\ +
      ", tx ); +}); + + +test( 'with attributes that apply to the whole list', function ( t ) { + let tx = "#(class#id) one\n\ +# two\n\ +# three"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. one
      2. \n\ +\t
      3. two
      4. \n\ +\t
      5. three
      6. \n\ +
      ", tx ); +}); + + +test( 'with id on the list', function ( t ) { + let tx = "#(#my-id) one\n\ +# two\n\ +# three"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. one
      2. \n\ +\t
      3. two
      4. \n\ +\t
      5. three
      6. \n\ +
      ", tx ); +}); + + +test( 'with class on the list', function ( t ) { + let tx = "#(my-class) one\n\ +# two\n\ +# three"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. one
      2. \n\ +\t
      3. two
      4. \n\ +\t
      5. three
      6. \n\ +
      ", tx ); +}); + + +test( 'with id on the list item', function ( t ) { + let tx = "# one\n\ +#(#my-item) two\n\ +# three"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. one
      2. \n\ +\t
      3. two
      4. \n\ +\t
      5. three
      6. \n\ +
      ", tx ); +}); + + +test( 'with attributes that apply to the first list item', function ( t ) { + let tx = "#.\n\ +#(class#id) one\n\ +# two\n\ +# three"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. one
      2. \n\ +\t
      3. two
      4. \n\ +\t
      5. three
      6. \n\ +
      ", tx ); +}); + + +test( 'changed from textism basics', function ( t ) { + let tx = "#{color:blue}.\n\ +# one\n\ +# two\n\ +# three"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. one
      2. \n\ +\t
      3. two
      4. \n\ +\t
      5. three
      6. \n\ +
      ", tx ); +}); + + +test( 'item and list attributes', function ( t ) { + let tx = "#(class#id).\n\ +#(first) Item 1\n\ +#(second) Item 2\n\ +#(third) Item 3"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. Item 1
      2. \n\ +\t
      3. Item 2
      4. \n\ +\t
      5. Item 3
      6. \n\ +
      ", tx ); +}); + + +test( 'with one padding-left increment', function ( t ) { + let tx = "#( one"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. one
      2. \n\ +
      ", tx ); +}); + + +test( 'with two padding-left increments', function ( t ) { + let tx = "#(( two"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. two
      2. \n\ +
      ", tx ); +}); + + +test( 'with one padding-right increment', function ( t ) { + let tx = "#) one"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. one
      2. \n\ +
      ", tx ); +}); + + +test( 'with padding-left and padding-right increments', function ( t ) { + let tx = "#() two"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. two
      2. \n\ +
      ", tx ); +}); + + +test( 'with padding-left and padding-right increments switched', function ( t ) { + let tx = "#)( two"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. two
      2. \n\ +
      ", tx ); +}); + + +test( 'list control items occuring-mid list should be ignored', function ( t ) { + let tx = "# one\n\ +# two\n\ +#.\n\ +# tree"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. one
      2. \n\ +\t
      3. two
      4. \n\ +\t
      5. tree
      6. \n\ +
      ", tx ); +}); + + +test( 'complicated case with continues and classes', function ( t ) { + let tx = "#(class#id).\n\ +#(first) Item 1\n\ +##.\n\ +##(sub1) Sub item 1\n\ +## Sub item 2\n\ +#(second) Item 2\n\ +##_(sub3) Sub item 3\n\ +## Sub item 4\n\n\ +#_(third) Item 3\n\ +##_(sub5) Sub item 5\n\ +## Sub item 6"; + t.is( textile.convert( tx ), + "
        \n\ +\t
      1. Item 1\n\ +\t
          \n\ +\t\t
        1. Sub item 1
        2. \n\ +\t\t
        3. Sub item 2
        4. \n\ +\t
      2. \n\ +\t
      3. Item 2\n\ +\t
          \n\ +\t\t
        1. Sub item 3
        2. \n\ +\t\t
        3. Sub item 4
        4. \n\ +\t
      4. \n\ +
      \n\ +
        \n\ +\t
      1. Item 3\n\ +\t
          \n\ +\t\t
        1. Sub item 5
        2. \n\ +\t\t
        3. Sub item 6
        4. \n\ +\t
      2. \n\ +
      ", tx ); +}); + diff --git a/test/options.js b/test/options.js index a6f744f..de6d20d 100644 --- a/test/options.js +++ b/test/options.js @@ -1,80 +1,61 @@ -test('jstextile options', function () { -var _saved_options = {}; -for ( var k in textile.defaults ) { _saved_options[k] = textile.defaults[k]; } - -var paragraph = "Some paragraph\nwith a linebreak."; - -// By default, inline linebreaks will be converted to html linebreaks -equal( - textile.convert(paragraph), - "

      Some paragraph
      \nwith a linebreak.

      " -); - -equal( - textile.convert(paragraph, { breaks: false }), - "

      Some paragraph\nwith a linebreak.

      " -); - - -// linebreak option works in tables -equal(textile.convert( // The textile - "|a|b\nc|d|\n"+ - "|a|b|c|\n" -), // Should output - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
      ab
      \nc
      d
      abc
      " -); -equal(textile.convert( // The textile - "|a|b\nc|d|\n"+ - "|a|b|c|\n" -, { breaks: false }), // Should output - "\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\t\n"+ - "\t\n"+ - "
      ab\ncd
      abc
      " -); - - - -// setting a global option makes it the subsequent default -textile.setOptions({ breaks: false }); -equal( - textile.convert(paragraph), - "

      Some paragraph\nwith a linebreak.

      " -); - -// the default has changed, but passing options overrides new defult -equal( - textile.convert(paragraph, { breaks: true }), - "

      Some paragraph
      \nwith a linebreak.

      " -); - -// ... and doesn't affect the new default -equal( - textile.convert(paragraph), - "

      Some paragraph\nwith a linebreak.

      " -); - +import test from 'ava'; +import textile from '../src'; + +test( 'jstextile options', function ( t ) { + var paragraph = 'Some paragraph\nwith a linebreak.'; + // By default, inline linebreaks will be converted to html linebreaks + t.is( textile.convert( paragraph ), + '

      Some paragraph
      \nwith a linebreak.

      ' ); + t.is( textile.convert( paragraph, { breaks: false }), + '

      Some paragraph\nwith a linebreak.

      ' ); +}); +test( 'jstextile options', function ( t ) { + // linebreak option works in tables + t.is( textile.convert( '|a|b\nc|d|\n|a|b|c|\n' ), + '\n' + + '\t\n' + + '\t\t\n' + + '\t\t\n' + + '\t\t\n' + + '\t\n' + + '\t\n' + + '\t\t\n' + + '\t\t\n' + + '\t\t\n' + + '\t\n' + + '
      ab
      \nc
      d
      abc
      ' ); + t.is( textile.convert( '|a|b\nc|d|\n|a|b|c|\n', { breaks: false }), + '\n' + + '\t\n' + + '\t\t\n' + + '\t\t\n' + + '\t\t\n' + + '\t\n' + + '\t\n' + + '\t\t\n' + + '\t\t\n' + + '\t\t\n' + + '\t\n' + + '
      ab\ncd
      abc
      ' ); +}); -// reset options -- -textile.setOptions( _saved_options ); +test( 'jstextile options', function ( t ) { + var paragraph = 'Some paragraph\nwith a linebreak.'; + var savedOptions = {}; + for ( var k in textile.defaults ) { + savedOptions[k] = textile.defaults[k]; + } + // setting a global option makes it the subsequent default + textile.setOptions({ breaks: false }); + t.is( textile.convert( paragraph ), + '

      Some paragraph\nwith a linebreak.

      ' ); + // the default has changed, but passing options overrides new defult + t.is( textile.convert( paragraph, { breaks: true }), + '

      Some paragraph
      \nwith a linebreak.

      ' ); + // ... and doesn't affect the new default + t.is( textile.convert( paragraph ), + '

      Some paragraph\nwith a linebreak.

      ' ); + // reset options -- + textile.setOptions( savedOptions ); }); diff --git a/test/poignant.js b/test/poignant.js new file mode 100644 index 0000000..4b361a8 --- /dev/null +++ b/test/poignant.js @@ -0,0 +1,56 @@ +// poignant.yml +import test from 'ava'; +import textile from '../src'; + +test( 'poignant:1', function ( t ) { + let tx = "h3. False\n\n\ +!\n\ + if plastic_cup\n\ + print \"Plastic cup is on the up 'n' up!\"\n\ + end\n\ +\n\n\ +If @plastic_cup@ contains either @nil@ or @false@, you won't see anything print to the screen. They're not on the @if@ guest list. So @if@ isn't going to run any of the code it's protecting.\n\n\ +But @nil@ and @false@ need not walk away in shame. They may be of questionable character, but @unless@ runs a smaller establishment that caters to the bedraggled. The @unless@ keyword has a policy of only allowing those with a negative charge in. Who are: @nil@ and @false@.\n\n\ +
      \n\
      +  unless plastic_cup\n\
      +    print \"Plastic cup is on the down low.\"\n\
      +  end\n\
      +
      \n\n\ +You can also use @if@ and @unless@ at the end of a single line of code, if that's all that is being protected.\n\n\ +
      \n\
      +  print \"Yeah, plastic cup is up again!\" if plastic_cup\n\
      +  print \"Hardly. It's down.\" unless plastic_cup\n\
      +
      \n\n\ +Now that you've met @false@, I'm sure you can see what's on next."; + t.is( textile.convert( tx ), + "

      False

      \n\ +

      \"Shape

      \n\ +

      The cat Trady Blix. Frozen in emptiness. Immaculate whiskers rigid. Placid eyes of lake. Tail of warm icicle. Sponsored by a Very Powerful Pause Button.

      \n\ +

      The darkness surrounding Blix can be called negative space. Hang on to that phrase. Let it suggest that the emptiness has a negative connotation. In a similar way, nil has a slightly sour note that it whistles.

      \n\ +

      Generally speaking, everything in Ruby has a positive charge to it. This spark flows through strings, numbers, regexps, all of it. Only two keywords wear a shady cloak: nil and false draggin us down.

      \n\ +

      You can test that charge with an if keyword. It looks very much like the do blocks we saw in the last chapter, in that both end with an end.

      \n\ +
      \n\
      +  if plastic_cup\n\
      +    print \"Plastic cup is on the up 'n' up!\"\n\
      +  end\n\
      +
      \n\ +

      If plastic_cup contains either nil or false, you won’t see anything print to the screen. They’re not on the if guest list. So if isn’t going to run any of the code it’s protecting.

      \n\ +

      But nil and false need not walk away in shame. They may be of questionable character, but unless runs a smaller establishment that caters to the bedraggled. The unless keyword has a policy of only allowing those with a negative charge in. Who are: nil and false.

      \n\ +
      \n\
      +  unless plastic_cup\n\
      +    print \"Plastic cup is on the down low.\"\n\
      +  end\n\
      +
      \n\ +

      You can also use if and unless at the end of a single line of code, if that’s all that is being protected.

      \n\ +
      \n\
      +  print \"Yeah, plastic cup is up again!\" if plastic_cup\n\
      +  print \"Hardly. It's down.\" unless plastic_cup\n\
      +
      \n\ +

      Now that you’ve met false, I’m sure you can see what’s on next.

      ", tx ); +}); + diff --git a/test/qunit/qunit.css b/test/qunit/qunit.css deleted file mode 100644 index b52b482..0000000 --- a/test/qunit/qunit.css +++ /dev/null @@ -1,231 +0,0 @@ -/** - * QUnit v1.10.0pre - A JavaScript Unit Testing Framework - * - * http://qunitjs.com - * - * Copyright 2012 jQuery Foundation and other contributors - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - */ - -/** Font Family and Sizes */ - -#qunit-tests, #qunit-header, #qunit-banner, #qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult { - font-family: "Helvetica Neue Light", "HelveticaNeue-Light", "Helvetica Neue", Calibri, Helvetica, Arial, sans-serif; -} - -#qunit-testrunner-toolbar, #qunit-userAgent, #qunit-testresult, #qunit-tests li { font-size: small; } -#qunit-tests { font-size: smaller; } - - -/** Resets */ - -#qunit-tests, #qunit-tests ol, #qunit-header, #qunit-banner, #qunit-userAgent, #qunit-testresult { - margin: 0; - padding: 0; -} - - -/** Header */ - -#qunit-header { - padding: 0.5em 0 0.5em 1em; - - color: #8699a4; - background-color: #0d3349; - - font-size: 1.5em; - line-height: 1em; - font-weight: normal; - - border-radius: 5px 5px 0 0; - -moz-border-radius: 5px 5px 0 0; - -webkit-border-top-right-radius: 5px; - -webkit-border-top-left-radius: 5px; -} - -#qunit-header a { - text-decoration: none; - color: #c2ccd1; -} - -#qunit-header a:hover, -#qunit-header a:focus { - color: #fff; -} - -#qunit-testrunner-toolbar label { - display: inline-block; - padding: 0 .5em 0 .1em; -} - -#qunit-banner { - height: 5px; -} - -#qunit-testrunner-toolbar { - padding: 0.5em 0 0.5em 2em; - color: #5E740B; - background-color: #eee; -} - -#qunit-userAgent { - padding: 0.5em 0 0.5em 2.5em; - background-color: #2b81af; - color: #fff; - text-shadow: rgba(0, 0, 0, 0.5) 2px 2px 1px; -} - - -/** Tests: Pass/Fail */ - -#qunit-tests { - list-style-position: inside; -} - -#qunit-tests li { - padding: 0.4em 0.5em 0.4em 2.5em; - border-bottom: 1px solid #fff; - list-style-position: inside; -} - -#qunit-tests.hidepass li.pass, #qunit-tests.hidepass li.running { - display: none; -} - -#qunit-tests li strong { - cursor: pointer; -} - -#qunit-tests li a { - padding: 0.5em; - color: #c2ccd1; - text-decoration: none; -} -#qunit-tests li a:hover, -#qunit-tests li a:focus { - color: #000; -} - -#qunit-tests ol { - margin-top: 0.5em; - padding: 0.5em; - - background-color: #fff; - - border-radius: 5px; - -moz-border-radius: 5px; - -webkit-border-radius: 5px; -} - -#qunit-tests table { - border-collapse: collapse; - margin-top: .2em; -} - -#qunit-tests th { - text-align: right; - vertical-align: top; - padding: 0 .5em 0 0; -} - -#qunit-tests td { - vertical-align: top; -} - -#qunit-tests pre { - margin: 0; - white-space: pre-wrap; - word-wrap: break-word; -} - -#qunit-tests del { - background-color: #e0f2be; - color: #374e0c; - text-decoration: none; -} - -#qunit-tests ins { - background-color: #ffcaca; - color: #500; - text-decoration: none; -} - -/*** Test Counts */ - -#qunit-tests b.counts { color: black; } -#qunit-tests b.passed { color: #5E740B; } -#qunit-tests b.failed { color: #710909; } - -#qunit-tests li li { - padding: 5px; - background-color: #fff; - border-bottom: none; - list-style-position: inside; -} - -/*** Passing Styles */ - -#qunit-tests li li.pass { - color: #3c510c; - background-color: #fff; - border-left: 10px solid #C6E746; -} - -#qunit-tests .pass { color: #528CE0; background-color: #D2E0E6; } -#qunit-tests .pass .test-name { color: #366097; } - -#qunit-tests .pass .test-actual, -#qunit-tests .pass .test-expected { color: #999999; } - -#qunit-banner.qunit-pass { background-color: #C6E746; } - -/*** Failing Styles */ - -#qunit-tests li li.fail { - color: #710909; - background-color: #fff; - border-left: 10px solid #EE5757; - white-space: pre; -} - -#qunit-tests > li:last-child { - border-radius: 0 0 5px 5px; - -moz-border-radius: 0 0 5px 5px; - -webkit-border-bottom-right-radius: 5px; - -webkit-border-bottom-left-radius: 5px; -} - -#qunit-tests .fail { color: #000000; background-color: #EE5757; } -#qunit-tests .fail .test-name, -#qunit-tests .fail .module-name { color: #000000; } - -#qunit-tests .fail .test-actual { color: #EE5757; } -#qunit-tests .fail .test-expected { color: green; } - -#qunit-banner.qunit-fail { background-color: #EE5757; } - - -/** Result */ - -#qunit-testresult { - padding: 0.5em 0.5em 0.5em 2.5em; - - color: #2b81af; - background-color: #D2E0E6; - - border-bottom: 1px solid white; -} -#qunit-testresult .module-name { - font-weight: bold; -} - -/** Fixture */ - -#qunit-fixture { - position: absolute; - top: -10000px; - left: -10000px; - width: 1000px; - height: 1000px; -} diff --git a/test/qunit/qunit.js b/test/qunit/qunit.js deleted file mode 100644 index bed5f45..0000000 --- a/test/qunit/qunit.js +++ /dev/null @@ -1,1934 +0,0 @@ -/** - * QUnit v1.10.0pre - A JavaScript Unit Testing Framework - * - * http://qunitjs.com - * - * Copyright 2012 jQuery Foundation and other contributors - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - */ - -(function( window ) { - -var QUnit, - config, - onErrorFnPrev, - testId = 0, - fileName = (sourceFromStacktrace( 0 ) || "" ).replace(/(:\d+)+\)?/, "").replace(/.+\//, ""), - toString = Object.prototype.toString, - hasOwn = Object.prototype.hasOwnProperty, - // Keep a local reference to Date (GH-283) - Date = window.Date, - defined = { - setTimeout: typeof window.setTimeout !== "undefined", - sessionStorage: (function() { - var x = "qunit-test-string"; - try { - sessionStorage.setItem( x, x ); - sessionStorage.removeItem( x ); - return true; - } catch( e ) { - return false; - } - }()) -}; - -function Test( settings ) { - extend( this, settings ); - this.assertions = []; - this.testNumber = ++Test.count; -} - -Test.count = 0; - -Test.prototype = { - init: function() { - var a, b, li, - tests = id( "qunit-tests" ); - - if ( tests ) { - b = document.createElement( "strong" ); - b.innerHTML = this.name; - - // `a` initialized at top of scope - a = document.createElement( "a" ); - a.innerHTML = "Rerun"; - a.href = QUnit.url({ testNumber: this.testNumber }); - - li = document.createElement( "li" ); - li.appendChild( b ); - li.appendChild( a ); - li.className = "running"; - li.id = this.id = "qunit-test-output" + testId++; - - tests.appendChild( li ); - } - }, - setup: function() { - if ( this.module !== config.previousModule ) { - if ( config.previousModule ) { - runLoggingCallbacks( "moduleDone", QUnit, { - name: config.previousModule, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all - }); - } - config.previousModule = this.module; - config.moduleStats = { all: 0, bad: 0 }; - runLoggingCallbacks( "moduleStart", QUnit, { - name: this.module - }); - } else if ( config.autorun ) { - runLoggingCallbacks( "moduleStart", QUnit, { - name: this.module - }); - } - - config.current = this; - - this.testEnvironment = extend({ - setup: function() {}, - teardown: function() {} - }, this.moduleTestEnvironment ); - - runLoggingCallbacks( "testStart", QUnit, { - name: this.testName, - module: this.module - }); - - // allow utility functions to access the current test environment - // TODO why?? - QUnit.current_testEnvironment = this.testEnvironment; - - if ( !config.pollution ) { - saveGlobal(); - } - if ( config.notrycatch ) { - this.testEnvironment.setup.call( this.testEnvironment ); - return; - } - try { - this.testEnvironment.setup.call( this.testEnvironment ); - } catch( e ) { - QUnit.pushFailure( "Setup failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); - } - }, - run: function() { - config.current = this; - - var running = id( "qunit-testresult" ); - - if ( running ) { - running.innerHTML = "Running:
      " + this.name; - } - - if ( this.async ) { - QUnit.stop(); - } - - if ( config.notrycatch ) { - this.callback.call( this.testEnvironment, QUnit.assert ); - return; - } - - try { - this.callback.call( this.testEnvironment, QUnit.assert ); - } catch( e ) { - QUnit.pushFailure( "Died on test #" + (this.assertions.length + 1) + " " + this.stack + ": " + e.message, extractStacktrace( e, 0 ) ); - // else next test will carry the responsibility - saveGlobal(); - - // Restart the tests if they're blocking - if ( config.blocking ) { - QUnit.start(); - } - } - }, - teardown: function() { - config.current = this; - if ( config.notrycatch ) { - this.testEnvironment.teardown.call( this.testEnvironment ); - return; - } else { - try { - this.testEnvironment.teardown.call( this.testEnvironment ); - } catch( e ) { - QUnit.pushFailure( "Teardown failed on " + this.testName + ": " + e.message, extractStacktrace( e, 1 ) ); - } - } - checkPollution(); - }, - finish: function() { - config.current = this; - if ( config.requireExpects && this.expected == null ) { - QUnit.pushFailure( "Expected number of assertions to be defined, but expect() was not called.", this.stack ); - } else if ( this.expected != null && this.expected != this.assertions.length ) { - QUnit.pushFailure( "Expected " + this.expected + " assertions, but " + this.assertions.length + " were run", this.stack ); - } else if ( this.expected == null && !this.assertions.length ) { - QUnit.pushFailure( "Expected at least one assertion, but none were run - call expect(0) to accept zero assertions.", this.stack ); - } - - var assertion, a, b, i, li, ol, - test = this, - good = 0, - bad = 0, - tests = id( "qunit-tests" ); - - config.stats.all += this.assertions.length; - config.moduleStats.all += this.assertions.length; - - if ( tests ) { - ol = document.createElement( "ol" ); - - for ( i = 0; i < this.assertions.length; i++ ) { - assertion = this.assertions[i]; - - li = document.createElement( "li" ); - li.className = assertion.result ? "pass" : "fail"; - li.innerHTML = assertion.message || ( assertion.result ? "okay" : "failed" ); - ol.appendChild( li ); - - if ( assertion.result ) { - good++; - } else { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - - // store result when possible - if ( QUnit.config.reorder && defined.sessionStorage ) { - if ( bad ) { - sessionStorage.setItem( "qunit-test-" + this.module + "-" + this.testName, bad ); - } else { - sessionStorage.removeItem( "qunit-test-" + this.module + "-" + this.testName ); - } - } - - if ( bad === 0 ) { - ol.style.display = "none"; - } - - // `b` initialized at top of scope - b = document.createElement( "strong" ); - b.innerHTML = this.name + " (" + bad + ", " + good + ", " + this.assertions.length + ")"; - - addEvent(b, "click", function() { - var next = b.nextSibling.nextSibling, - display = next.style.display; - next.style.display = display === "none" ? "block" : "none"; - }); - - addEvent(b, "dblclick", function( e ) { - var target = e && e.target ? e.target : window.event.srcElement; - if ( target.nodeName.toLowerCase() == "span" || target.nodeName.toLowerCase() == "b" ) { - target = target.parentNode; - } - if ( window.location && target.nodeName.toLowerCase() === "strong" ) { - window.location = QUnit.url({ testNumber: test.testNumber }); - } - }); - - // `li` initialized at top of scope - li = id( this.id ); - li.className = bad ? "fail" : "pass"; - li.removeChild( li.firstChild ); - a = li.firstChild; - li.appendChild( b ); - li.appendChild ( a ); - li.appendChild( ol ); - - } else { - for ( i = 0; i < this.assertions.length; i++ ) { - if ( !this.assertions[i].result ) { - bad++; - config.stats.bad++; - config.moduleStats.bad++; - } - } - } - - runLoggingCallbacks( "testDone", QUnit, { - name: this.testName, - module: this.module, - failed: bad, - passed: this.assertions.length - bad, - total: this.assertions.length - }); - - QUnit.reset(); - - config.current = undefined; - }, - - queue: function() { - var bad, - test = this; - - synchronize(function() { - test.init(); - }); - function run() { - // each of these can by async - synchronize(function() { - test.setup(); - }); - synchronize(function() { - test.run(); - }); - synchronize(function() { - test.teardown(); - }); - synchronize(function() { - test.finish(); - }); - } - - // `bad` initialized at top of scope - // defer when previous test run passed, if storage is available - bad = QUnit.config.reorder && defined.sessionStorage && - +sessionStorage.getItem( "qunit-test-" + this.module + "-" + this.testName ); - - if ( bad ) { - run(); - } else { - synchronize( run, true ); - } - } -}; - -// Root QUnit object. -// `QUnit` initialized at top of scope -QUnit = { - - // call on start of module test to prepend name to all tests - module: function( name, testEnvironment ) { - config.currentModule = name; - config.currentModuleTestEnviroment = testEnvironment; - }, - - asyncTest: function( testName, expected, callback ) { - if ( arguments.length === 2 ) { - callback = expected; - expected = null; - } - - QUnit.test( testName, expected, callback, true ); - }, - - test: function( testName, expected, callback, async ) { - var test, - name = "" + escapeInnerText( testName ) + ""; - - if ( arguments.length === 2 ) { - callback = expected; - expected = null; - } - - if ( config.currentModule ) { - name = "" + config.currentModule + ": " + name; - } - - test = new Test({ - name: name, - testName: testName, - expected: expected, - async: async, - callback: callback, - module: config.currentModule, - moduleTestEnvironment: config.currentModuleTestEnviroment, - stack: sourceFromStacktrace( 2 ) - }); - - if ( !validTest( test ) ) { - return; - } - - test.queue(); - }, - - // Specify the number of expected assertions to gurantee that failed test (no assertions are run at all) don't slip through. - expect: function( asserts ) { - config.current.expected = asserts; - }, - - start: function( count ) { - config.semaphore -= count || 1; - // don't start until equal number of stop-calls - if ( config.semaphore > 0 ) { - return; - } - // ignore if start is called more often then stop - if ( config.semaphore < 0 ) { - config.semaphore = 0; - } - // A slight delay, to avoid any current callbacks - if ( defined.setTimeout ) { - window.setTimeout(function() { - if ( config.semaphore > 0 ) { - return; - } - if ( config.timeout ) { - clearTimeout( config.timeout ); - } - - config.blocking = false; - process( true ); - }, 13); - } else { - config.blocking = false; - process( true ); - } - }, - - stop: function( count ) { - config.semaphore += count || 1; - config.blocking = true; - - if ( config.testTimeout && defined.setTimeout ) { - clearTimeout( config.timeout ); - config.timeout = window.setTimeout(function() { - QUnit.ok( false, "Test timed out" ); - config.semaphore = 1; - QUnit.start(); - }, config.testTimeout ); - } - } -}; - -// Asssert helpers -// All of these must call either QUnit.push() or manually do: -// - runLoggingCallbacks( "log", .. ); -// - config.current.assertions.push({ .. }); -QUnit.assert = { - /** - * Asserts rough true-ish result. - * @name ok - * @function - * @example ok( "asdfasdf".length > 5, "There must be at least 5 chars" ); - */ - ok: function( result, msg ) { - if ( !config.current ) { - throw new Error( "ok() assertion outside test context, was " + sourceFromStacktrace(2) ); - } - result = !!result; - - var source, - details = { - result: result, - message: msg - }; - - msg = escapeInnerText( msg || (result ? "okay" : "failed" ) ); - msg = "" + msg + ""; - - if ( !result ) { - source = sourceFromStacktrace( 2 ); - if ( source ) { - details.source = source; - msg += "
      Source:
      " + escapeInnerText( source ) + "
      "; - } - } - runLoggingCallbacks( "log", QUnit, details ); - config.current.assertions.push({ - result: result, - message: msg - }); - }, - - /** - * Assert that the first two arguments are equal, with an optional message. - * Prints out both actual and expected values. - * @name equal - * @function - * @example equal( format( "Received {0} bytes.", 2), "Received 2 bytes.", "format() replaces {0} with next argument" ); - */ - equal: function( actual, expected, message ) { - QUnit.push( expected == actual, actual, expected, message ); - }, - - /** - * @name notEqual - * @function - */ - notEqual: function( actual, expected, message ) { - QUnit.push( expected != actual, actual, expected, message ); - }, - - /** - * @name deepEqual - * @function - */ - deepEqual: function( actual, expected, message ) { - QUnit.push( QUnit.equiv(actual, expected), actual, expected, message ); - }, - - /** - * @name notDeepEqual - * @function - */ - notDeepEqual: function( actual, expected, message ) { - QUnit.push( !QUnit.equiv(actual, expected), actual, expected, message ); - }, - - /** - * @name strictEqual - * @function - */ - strictEqual: function( actual, expected, message ) { - QUnit.push( expected === actual, actual, expected, message ); - }, - - /** - * @name notStrictEqual - * @function - */ - notStrictEqual: function( actual, expected, message ) { - QUnit.push( expected !== actual, actual, expected, message ); - }, - - throws: function( block, expected, message ) { - var actual, - ok = false; - - // 'expected' is optional - if ( typeof expected === "string" ) { - message = expected; - expected = null; - } - - config.current.ignoreGlobalErrors = true; - try { - block.call( config.current.testEnvironment ); - } catch (e) { - actual = e; - } - config.current.ignoreGlobalErrors = false; - - if ( actual ) { - // we don't want to validate thrown error - if ( !expected ) { - ok = true; - // expected is a regexp - } else if ( QUnit.objectType( expected ) === "regexp" ) { - ok = expected.test( actual ); - // expected is a constructor - } else if ( actual instanceof expected ) { - ok = true; - // expected is a validation function which returns true is validation passed - } else if ( expected.call( {}, actual ) === true ) { - ok = true; - } - - QUnit.push( ok, actual, null, message ); - } else { - QUnit.pushFailure( message, null, 'No exception was thrown.' ); - } - } -}; - -/** - * @deprecate since 1.8.0 - * Kept assertion helpers in root for backwards compatibility - */ -extend( QUnit, QUnit.assert ); - -/** - * @deprecated since 1.9.0 - * Kept global "raises()" for backwards compatibility - */ -QUnit.raises = QUnit.assert.throws; - -/** - * @deprecated since 1.0.0, replaced with error pushes since 1.3.0 - * Kept to avoid TypeErrors for undefined methods. - */ -QUnit.equals = function() { - QUnit.push( false, false, false, "QUnit.equals has been deprecated since 2009 (e88049a0), use QUnit.equal instead" ); -}; -QUnit.same = function() { - QUnit.push( false, false, false, "QUnit.same has been deprecated since 2009 (e88049a0), use QUnit.deepEqual instead" ); -}; - -// We want access to the constructor's prototype -(function() { - function F() {} - F.prototype = QUnit; - QUnit = new F(); - // Make F QUnit's constructor so that we can add to the prototype later - QUnit.constructor = F; -}()); - -/** - * Config object: Maintain internal state - * Later exposed as QUnit.config - * `config` initialized at top of scope - */ -config = { - // The queue of tests to run - queue: [], - - // block until document ready - blocking: true, - - // when enabled, show only failing tests - // gets persisted through sessionStorage and can be changed in UI via checkbox - hidepassed: false, - - // by default, run previously failed tests first - // very useful in combination with "Hide passed tests" checked - reorder: true, - - // by default, modify document.title when suite is done - altertitle: true, - - // when enabled, all tests must call expect() - requireExpects: false, - - // add checkboxes that are persisted in the query-string - // when enabled, the id is set to `true` as a `QUnit.config` property - urlConfig: [ - { - id: "noglobals", - label: "Check for Globals", - tooltip: "Enabling this will test if any test introduces new properties on the `window` object. Stored as query-strings." - }, - { - id: "notrycatch", - label: "No try-catch", - tooltip: "Enabling this will run tests outside of a try-catch block. Makes debugging exceptions in IE reasonable. Stored as query-strings." - } - ], - - // logging callback queues - begin: [], - done: [], - log: [], - testStart: [], - testDone: [], - moduleStart: [], - moduleDone: [] -}; - -// Initialize more QUnit.config and QUnit.urlParams -(function() { - var i, - location = window.location || { search: "", protocol: "file:" }, - params = location.search.slice( 1 ).split( "&" ), - length = params.length, - urlParams = {}, - current; - - if ( params[ 0 ] ) { - for ( i = 0; i < length; i++ ) { - current = params[ i ].split( "=" ); - current[ 0 ] = decodeURIComponent( current[ 0 ] ); - // allow just a key to turn on a flag, e.g., test.html?noglobals - current[ 1 ] = current[ 1 ] ? decodeURIComponent( current[ 1 ] ) : true; - urlParams[ current[ 0 ] ] = current[ 1 ]; - } - } - - QUnit.urlParams = urlParams; - - // String search anywhere in moduleName+testName - config.filter = urlParams.filter; - - // Exact match of the module name - config.module = urlParams.module; - - config.testNumber = parseInt( urlParams.testNumber, 10 ) || null; - - // Figure out if we're running the tests from a server or not - QUnit.isLocal = location.protocol === "file:"; -}()); - -// Export global variables, unless an 'exports' object exists, -// in that case we assume we're in CommonJS (dealt with on the bottom of the script) -if ( typeof exports === "undefined" ) { - extend( window, QUnit ); - - // Expose QUnit object - window.QUnit = QUnit; -} - -// Extend QUnit object, -// these after set here because they should not be exposed as global functions -extend( QUnit, { - config: config, - - // Initialize the configuration options - init: function() { - extend( config, { - stats: { all: 0, bad: 0 }, - moduleStats: { all: 0, bad: 0 }, - started: +new Date(), - updateRate: 1000, - blocking: false, - autostart: true, - autorun: false, - filter: "", - queue: [], - semaphore: 0 - }); - - var tests, banner, result, - qunit = id( "qunit" ); - - if ( qunit ) { - qunit.innerHTML = - "

      " + escapeInnerText( document.title ) + "

      " + - "

      " + - "
      " + - "

      " + - "
        "; - } - - tests = id( "qunit-tests" ); - banner = id( "qunit-banner" ); - result = id( "qunit-testresult" ); - - if ( tests ) { - tests.innerHTML = ""; - } - - if ( banner ) { - banner.className = ""; - } - - if ( result ) { - result.parentNode.removeChild( result ); - } - - if ( tests ) { - result = document.createElement( "p" ); - result.id = "qunit-testresult"; - result.className = "result"; - tests.parentNode.insertBefore( result, tests ); - result.innerHTML = "Running...
         "; - } - }, - - // Resets the test setup. Useful for tests that modify the DOM. - // If jQuery is available, uses jQuery's html(), otherwise just innerHTML. - reset: function() { - var fixture; - - if ( window.jQuery ) { - jQuery( "#qunit-fixture" ).html( config.fixture ); - } else { - fixture = id( "qunit-fixture" ); - if ( fixture ) { - fixture.innerHTML = config.fixture; - } - } - }, - - // Trigger an event on an element. - // @example triggerEvent( document.body, "click" ); - triggerEvent: function( elem, type, event ) { - if ( document.createEvent ) { - event = document.createEvent( "MouseEvents" ); - event.initMouseEvent(type, true, true, elem.ownerDocument.defaultView, - 0, 0, 0, 0, 0, false, false, false, false, 0, null); - - elem.dispatchEvent( event ); - } else if ( elem.fireEvent ) { - elem.fireEvent( "on" + type ); - } - }, - - // Safe object type checking - is: function( type, obj ) { - return QUnit.objectType( obj ) == type; - }, - - objectType: function( obj ) { - if ( typeof obj === "undefined" ) { - return "undefined"; - // consider: typeof null === object - } - if ( obj === null ) { - return "null"; - } - - var type = toString.call( obj ).match(/^\[object\s(.*)\]$/)[1] || ""; - - switch ( type ) { - case "Number": - if ( isNaN(obj) ) { - return "nan"; - } - return "number"; - case "String": - case "Boolean": - case "Array": - case "Date": - case "RegExp": - case "Function": - return type.toLowerCase(); - } - if ( typeof obj === "object" ) { - return "object"; - } - return undefined; - }, - - push: function( result, actual, expected, message ) { - if ( !config.current ) { - throw new Error( "assertion outside test context, was " + sourceFromStacktrace() ); - } - - var output, source, - details = { - result: result, - message: message, - actual: actual, - expected: expected - }; - - message = escapeInnerText( message ) || ( result ? "okay" : "failed" ); - message = "" + message + ""; - output = message; - - if ( !result ) { - expected = escapeInnerText( QUnit.jsDump.parse(expected) ); - actual = escapeInnerText( QUnit.jsDump.parse(actual) ); - output += ""; - - if ( actual != expected ) { - output += ""; - output += ""; - } - - source = sourceFromStacktrace(); - - if ( source ) { - details.source = source; - output += ""; - } - - output += "
        Expected:
        " + expected + "
        Result:
        " + actual + "
        Diff:
        " + QUnit.diff( expected, actual ) + "
        Source:
        " + escapeInnerText( source ) + "
        "; - } - - runLoggingCallbacks( "log", QUnit, details ); - - config.current.assertions.push({ - result: !!result, - message: output - }); - }, - - pushFailure: function( message, source, actual ) { - if ( !config.current ) { - throw new Error( "pushFailure() assertion outside test context, was " + sourceFromStacktrace(2) ); - } - - var output, - details = { - result: false, - message: message - }; - - message = escapeInnerText( message ) || "error"; - message = "" + message + ""; - output = message; - - output += ""; - - if ( actual ) { - output += ""; - } - - if ( source ) { - details.source = source; - output += ""; - } - - output += "
        Result:
        " + escapeInnerText( actual ) + "
        Source:
        " + escapeInnerText( source ) + "
        "; - - runLoggingCallbacks( "log", QUnit, details ); - - config.current.assertions.push({ - result: false, - message: output - }); - }, - - url: function( params ) { - params = extend( extend( {}, QUnit.urlParams ), params ); - var key, - querystring = "?"; - - for ( key in params ) { - if ( !hasOwn.call( params, key ) ) { - continue; - } - querystring += encodeURIComponent( key ) + "=" + - encodeURIComponent( params[ key ] ) + "&"; - } - return window.location.pathname + querystring.slice( 0, -1 ); - }, - - extend: extend, - id: id, - addEvent: addEvent - // load, equiv, jsDump, diff: Attached later -}); - -/** - * @deprecated: Created for backwards compatibility with test runner that set the hook function - * into QUnit.{hook}, instead of invoking it and passing the hook function. - * QUnit.constructor is set to the empty F() above so that we can add to it's prototype here. - * Doing this allows us to tell if the following methods have been overwritten on the actual - * QUnit object. - */ -extend( QUnit.constructor.prototype, { - - // Logging callbacks; all receive a single argument with the listed properties - // run test/logs.html for any related changes - begin: registerLoggingCallback( "begin" ), - - // done: { failed, passed, total, runtime } - done: registerLoggingCallback( "done" ), - - // log: { result, actual, expected, message } - log: registerLoggingCallback( "log" ), - - // testStart: { name } - testStart: registerLoggingCallback( "testStart" ), - - // testDone: { name, failed, passed, total } - testDone: registerLoggingCallback( "testDone" ), - - // moduleStart: { name } - moduleStart: registerLoggingCallback( "moduleStart" ), - - // moduleDone: { name, failed, passed, total } - moduleDone: registerLoggingCallback( "moduleDone" ) -}); - -if ( typeof document === "undefined" || document.readyState === "complete" ) { - config.autorun = true; -} - -QUnit.load = function() { - runLoggingCallbacks( "begin", QUnit, {} ); - - // Initialize the config, saving the execution queue - var banner, filter, i, label, len, main, ol, toolbar, userAgent, val, urlConfigCheckboxes, - urlConfigHtml = "", - oldconfig = extend( {}, config ); - - QUnit.init(); - extend(config, oldconfig); - - config.blocking = false; - - len = config.urlConfig.length; - - for ( i = 0; i < len; i++ ) { - val = config.urlConfig[i]; - if ( typeof val === "string" ) { - val = { - id: val, - label: val, - tooltip: "[no tooltip available]" - }; - } - config[ val.id ] = QUnit.urlParams[ val.id ]; - urlConfigHtml += ""; - } - - // `userAgent` initialized at top of scope - userAgent = id( "qunit-userAgent" ); - if ( userAgent ) { - userAgent.innerHTML = navigator.userAgent; - } - - // `banner` initialized at top of scope - banner = id( "qunit-header" ); - if ( banner ) { - banner.innerHTML = "" + banner.innerHTML + " "; - } - - // `toolbar` initialized at top of scope - toolbar = id( "qunit-testrunner-toolbar" ); - if ( toolbar ) { - // `filter` initialized at top of scope - filter = document.createElement( "input" ); - filter.type = "checkbox"; - filter.id = "qunit-filter-pass"; - - addEvent( filter, "click", function() { - var tmp, - ol = document.getElementById( "qunit-tests" ); - - if ( filter.checked ) { - ol.className = ol.className + " hidepass"; - } else { - tmp = " " + ol.className.replace( /[\n\t\r]/g, " " ) + " "; - ol.className = tmp.replace( / hidepass /, " " ); - } - if ( defined.sessionStorage ) { - if (filter.checked) { - sessionStorage.setItem( "qunit-filter-passed-tests", "true" ); - } else { - sessionStorage.removeItem( "qunit-filter-passed-tests" ); - } - } - }); - - if ( config.hidepassed || defined.sessionStorage && sessionStorage.getItem( "qunit-filter-passed-tests" ) ) { - filter.checked = true; - // `ol` initialized at top of scope - ol = document.getElementById( "qunit-tests" ); - ol.className = ol.className + " hidepass"; - } - toolbar.appendChild( filter ); - - // `label` initialized at top of scope - label = document.createElement( "label" ); - label.setAttribute( "for", "qunit-filter-pass" ); - label.setAttribute( "title", "Only show tests and assertons that fail. Stored in sessionStorage." ); - label.innerHTML = "Hide passed tests"; - toolbar.appendChild( label ); - - urlConfigCheckboxes = document.createElement( 'span' ); - urlConfigCheckboxes.innerHTML = urlConfigHtml; - addEvent( urlConfigCheckboxes, "change", function( event ) { - var params = {}; - params[ event.target.name ] = event.target.checked ? true : undefined; - window.location = QUnit.url( params ); - }); - toolbar.appendChild( urlConfigCheckboxes ); - } - - // `main` initialized at top of scope - main = id( "qunit-fixture" ); - if ( main ) { - config.fixture = main.innerHTML; - } - - if ( config.autostart ) { - QUnit.start(); - } -}; - -addEvent( window, "load", QUnit.load ); - -// `onErrorFnPrev` initialized at top of scope -// Preserve other handlers -onErrorFnPrev = window.onerror; - -// Cover uncaught exceptions -// Returning true will surpress the default browser handler, -// returning false will let it run. -window.onerror = function ( error, filePath, linerNr ) { - var ret = false; - if ( onErrorFnPrev ) { - ret = onErrorFnPrev( error, filePath, linerNr ); - } - - // Treat return value as window.onerror itself does, - // Only do our handling if not surpressed. - if ( ret !== true ) { - if ( QUnit.config.current ) { - if ( QUnit.config.current.ignoreGlobalErrors ) { - return true; - } - QUnit.pushFailure( error, filePath + ":" + linerNr ); - } else { - QUnit.test( "global failure", function() { - QUnit.pushFailure( error, filePath + ":" + linerNr ); - }); - } - return false; - } - - return ret; -}; - -function done() { - config.autorun = true; - - // Log the last module results - if ( config.currentModule ) { - runLoggingCallbacks( "moduleDone", QUnit, { - name: config.currentModule, - failed: config.moduleStats.bad, - passed: config.moduleStats.all - config.moduleStats.bad, - total: config.moduleStats.all - }); - } - - var i, key, - banner = id( "qunit-banner" ), - tests = id( "qunit-tests" ), - runtime = +new Date() - config.started, - passed = config.stats.all - config.stats.bad, - html = [ - "Tests completed in ", - runtime, - " milliseconds.
        ", - "", - passed, - " tests of ", - config.stats.all, - " passed, ", - config.stats.bad, - " failed." - ].join( "" ); - - if ( banner ) { - banner.className = ( config.stats.bad ? "qunit-fail" : "qunit-pass" ); - } - - if ( tests ) { - id( "qunit-testresult" ).innerHTML = html; - } - - if ( config.altertitle && typeof document !== "undefined" && document.title ) { - // show ✖ for good, ✔ for bad suite result in title - // use escape sequences in case file gets loaded with non-utf-8-charset - document.title = [ - ( config.stats.bad ? "\u2716" : "\u2714" ), - document.title.replace( /^[\u2714\u2716] /i, "" ) - ].join( " " ); - } - - // clear own sessionStorage items if all tests passed - if ( config.reorder && defined.sessionStorage && config.stats.bad === 0 ) { - // `key` & `i` initialized at top of scope - for ( i = 0; i < sessionStorage.length; i++ ) { - key = sessionStorage.key( i++ ); - if ( key.indexOf( "qunit-test-" ) === 0 ) { - sessionStorage.removeItem( key ); - } - } - } - - runLoggingCallbacks( "done", QUnit, { - failed: config.stats.bad, - passed: passed, - total: config.stats.all, - runtime: runtime - }); -} - -/** @return Boolean: true if this test should be ran */ -function validTest( test ) { - var include, - filter = config.filter && config.filter.toLowerCase(), - module = config.module && config.module.toLowerCase(), - fullName = (test.module + ": " + test.testName).toLowerCase(); - - if ( config.testNumber ) { - return test.testNumber === config.testNumber; - } - - if ( module && ( !test.module || test.module.toLowerCase() !== module ) ) { - return false; - } - - if ( !filter ) { - return true; - } - - include = filter.charAt( 0 ) !== "!"; - if ( !include ) { - filter = filter.slice( 1 ); - } - - // If the filter matches, we need to honour include - if ( fullName.indexOf( filter ) !== -1 ) { - return include; - } - - // Otherwise, do the opposite - return !include; -} - -// so far supports only Firefox, Chrome and Opera (buggy), Safari (for real exceptions) -// Later Safari and IE10 are supposed to support error.stack as well -// See also https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error/Stack -function extractStacktrace( e, offset ) { - offset = offset === undefined ? 3 : offset; - - var stack, include, i, regex; - - if ( e.stacktrace ) { - // Opera - return e.stacktrace.split( "\n" )[ offset + 3 ]; - } else if ( e.stack ) { - // Firefox, Chrome - stack = e.stack.split( "\n" ); - if (/^error$/i.test( stack[0] ) ) { - stack.shift(); - } - if ( fileName ) { - include = []; - for ( i = offset; i < stack.length; i++ ) { - if ( stack[ i ].indexOf( fileName ) != -1 ) { - break; - } - include.push( stack[ i ] ); - } - if ( include.length ) { - return include.join( "\n" ); - } - } - return stack[ offset ]; - } else if ( e.sourceURL ) { - // Safari, PhantomJS - // hopefully one day Safari provides actual stacktraces - // exclude useless self-reference for generated Error objects - if ( /qunit.js$/.test( e.sourceURL ) ) { - return; - } - // for actual exceptions, this is useful - return e.sourceURL + ":" + e.line; - } -} -function sourceFromStacktrace( offset ) { - try { - throw new Error(); - } catch ( e ) { - return extractStacktrace( e, offset ); - } -} - -function escapeInnerText( s ) { - if ( !s ) { - return ""; - } - s = s + ""; - return s.replace( /[\&<>]/g, function( s ) { - switch( s ) { - case "&": return "&"; - case "<": return "<"; - case ">": return ">"; - default: return s; - } - }); -} - -function synchronize( callback, last ) { - config.queue.push( callback ); - - if ( config.autorun && !config.blocking ) { - process( last ); - } -} - -function process( last ) { - function next() { - process( last ); - } - var start = new Date().getTime(); - config.depth = config.depth ? config.depth + 1 : 1; - - while ( config.queue.length && !config.blocking ) { - if ( !defined.setTimeout || config.updateRate <= 0 || ( ( new Date().getTime() - start ) < config.updateRate ) ) { - config.queue.shift()(); - } else { - window.setTimeout( next, 13 ); - break; - } - } - config.depth--; - if ( last && !config.blocking && !config.queue.length && config.depth === 0 ) { - done(); - } -} - -function saveGlobal() { - config.pollution = []; - - if ( config.noglobals ) { - for ( var key in window ) { - // in Opera sometimes DOM element ids show up here, ignore them - if ( !hasOwn.call( window, key ) || /^qunit-test-output/.test( key ) ) { - continue; - } - config.pollution.push( key ); - } - } -} - -function checkPollution( name ) { - var newGlobals, - deletedGlobals, - old = config.pollution; - - saveGlobal(); - - newGlobals = diff( config.pollution, old ); - if ( newGlobals.length > 0 ) { - QUnit.pushFailure( "Introduced global variable(s): " + newGlobals.join(", ") ); - } - - deletedGlobals = diff( old, config.pollution ); - if ( deletedGlobals.length > 0 ) { - QUnit.pushFailure( "Deleted global variable(s): " + deletedGlobals.join(", ") ); - } -} - -// returns a new Array with the elements that are in a but not in b -function diff( a, b ) { - var i, j, - result = a.slice(); - - for ( i = 0; i < result.length; i++ ) { - for ( j = 0; j < b.length; j++ ) { - if ( result[i] === b[j] ) { - result.splice( i, 1 ); - i--; - break; - } - } - } - return result; -} - -function extend( a, b ) { - for ( var prop in b ) { - if ( b[ prop ] === undefined ) { - delete a[ prop ]; - - // Avoid "Member not found" error in IE8 caused by setting window.constructor - } else if ( prop !== "constructor" || a !== window ) { - a[ prop ] = b[ prop ]; - } - } - - return a; -} - -function addEvent( elem, type, fn ) { - if ( elem.addEventListener ) { - elem.addEventListener( type, fn, false ); - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, fn ); - } else { - fn(); - } -} - -function id( name ) { - return !!( typeof document !== "undefined" && document && document.getElementById ) && - document.getElementById( name ); -} - -function registerLoggingCallback( key ) { - return function( callback ) { - config[key].push( callback ); - }; -} - -// Supports deprecated method of completely overwriting logging callbacks -function runLoggingCallbacks( key, scope, args ) { - //debugger; - var i, callbacks; - if ( QUnit.hasOwnProperty( key ) ) { - QUnit[ key ].call(scope, args ); - } else { - callbacks = config[ key ]; - for ( i = 0; i < callbacks.length; i++ ) { - callbacks[ i ].call( scope, args ); - } - } -} - -// Test for equality any JavaScript type. -// Author: Philippe Rathé -QUnit.equiv = (function() { - - // Call the o related callback with the given arguments. - function bindCallbacks( o, callbacks, args ) { - var prop = QUnit.objectType( o ); - if ( prop ) { - if ( QUnit.objectType( callbacks[ prop ] ) === "function" ) { - return callbacks[ prop ].apply( callbacks, args ); - } else { - return callbacks[ prop ]; // or undefined - } - } - } - - // the real equiv function - var innerEquiv, - // stack to decide between skip/abort functions - callers = [], - // stack to avoiding loops from circular referencing - parents = [], - - getProto = Object.getPrototypeOf || function ( obj ) { - return obj.__proto__; - }, - callbacks = (function () { - - // for string, boolean, number and null - function useStrictEquality( b, a ) { - if ( b instanceof a.constructor || a instanceof b.constructor ) { - // to catch short annotaion VS 'new' annotation of a - // declaration - // e.g. var i = 1; - // var j = new Number(1); - return a == b; - } else { - return a === b; - } - } - - return { - "string": useStrictEquality, - "boolean": useStrictEquality, - "number": useStrictEquality, - "null": useStrictEquality, - "undefined": useStrictEquality, - - "nan": function( b ) { - return isNaN( b ); - }, - - "date": function( b, a ) { - return QUnit.objectType( b ) === "date" && a.valueOf() === b.valueOf(); - }, - - "regexp": function( b, a ) { - return QUnit.objectType( b ) === "regexp" && - // the regex itself - a.source === b.source && - // and its modifers - a.global === b.global && - // (gmi) ... - a.ignoreCase === b.ignoreCase && - a.multiline === b.multiline; - }, - - // - skip when the property is a method of an instance (OOP) - // - abort otherwise, - // initial === would have catch identical references anyway - "function": function() { - var caller = callers[callers.length - 1]; - return caller !== Object && typeof caller !== "undefined"; - }, - - "array": function( b, a ) { - var i, j, len, loop; - - // b could be an object literal here - if ( QUnit.objectType( b ) !== "array" ) { - return false; - } - - len = a.length; - if ( len !== b.length ) { - // safe and faster - return false; - } - - // track reference to avoid circular references - parents.push( a ); - for ( i = 0; i < len; i++ ) { - loop = false; - for ( j = 0; j < parents.length; j++ ) { - if ( parents[j] === a[i] ) { - loop = true;// dont rewalk array - } - } - if ( !loop && !innerEquiv(a[i], b[i]) ) { - parents.pop(); - return false; - } - } - parents.pop(); - return true; - }, - - "object": function( b, a ) { - var i, j, loop, - // Default to true - eq = true, - aProperties = [], - bProperties = []; - - // comparing constructors is more strict than using - // instanceof - if ( a.constructor !== b.constructor ) { - // Allow objects with no prototype to be equivalent to - // objects with Object as their constructor. - if ( !(( getProto(a) === null && getProto(b) === Object.prototype ) || - ( getProto(b) === null && getProto(a) === Object.prototype ) ) ) { - return false; - } - } - - // stack constructor before traversing properties - callers.push( a.constructor ); - // track reference to avoid circular references - parents.push( a ); - - for ( i in a ) { // be strict: don't ensures hasOwnProperty - // and go deep - loop = false; - for ( j = 0; j < parents.length; j++ ) { - if ( parents[j] === a[i] ) { - // don't go down the same path twice - loop = true; - } - } - aProperties.push(i); // collect a's properties - - if (!loop && !innerEquiv( a[i], b[i] ) ) { - eq = false; - break; - } - } - - callers.pop(); // unstack, we are done - parents.pop(); - - for ( i in b ) { - bProperties.push( i ); // collect b's properties - } - - // Ensures identical properties name - return eq && innerEquiv( aProperties.sort(), bProperties.sort() ); - } - }; - }()); - - innerEquiv = function() { // can take multiple arguments - var args = [].slice.apply( arguments ); - if ( args.length < 2 ) { - return true; // end transition - } - - return (function( a, b ) { - if ( a === b ) { - return true; // catch the most you can - } else if ( a === null || b === null || typeof a === "undefined" || - typeof b === "undefined" || - QUnit.objectType(a) !== QUnit.objectType(b) ) { - return false; // don't lose time with error prone cases - } else { - return bindCallbacks(a, callbacks, [ b, a ]); - } - - // apply transition with (1..n) arguments - }( args[0], args[1] ) && arguments.callee.apply( this, args.splice(1, args.length - 1 )) ); - }; - - return innerEquiv; -}()); - -/** - * jsDump Copyright (c) 2008 Ariel Flesler - aflesler(at)gmail(dot)com | - * http://flesler.blogspot.com Licensed under BSD - * (http://www.opensource.org/licenses/bsd-license.php) Date: 5/15/2008 - * - * @projectDescription Advanced and extensible data dumping for Javascript. - * @version 1.0.0 - * @author Ariel Flesler - * @link {http://flesler.blogspot.com/2008/05/jsdump-pretty-dump-of-any-javascript.html} - */ -QUnit.jsDump = (function() { - function quote( str ) { - return '"' + str.toString().replace( /"/g, '\\"' ) + '"'; - } - function literal( o ) { - return o + ""; - } - function join( pre, arr, post ) { - var s = jsDump.separator(), - base = jsDump.indent(), - inner = jsDump.indent(1); - if ( arr.join ) { - arr = arr.join( "," + s + inner ); - } - if ( !arr ) { - return pre + post; - } - return [ pre, inner + arr, base + post ].join(s); - } - function array( arr, stack ) { - var i = arr.length, ret = new Array(i); - this.up(); - while ( i-- ) { - ret[i] = this.parse( arr[i] , undefined , stack); - } - this.down(); - return join( "[", ret, "]" ); - } - - var reName = /^function (\w+)/, - jsDump = { - parse: function( obj, type, stack ) { //type is used mostly internally, you can fix a (custom)type in advance - stack = stack || [ ]; - var inStack, res, - parser = this.parsers[ type || this.typeOf(obj) ]; - - type = typeof parser; - inStack = inArray( obj, stack ); - - if ( inStack != -1 ) { - return "recursion(" + (inStack - stack.length) + ")"; - } - //else - if ( type == "function" ) { - stack.push( obj ); - res = parser.call( this, obj, stack ); - stack.pop(); - return res; - } - // else - return ( type == "string" ) ? parser : this.parsers.error; - }, - typeOf: function( obj ) { - var type; - if ( obj === null ) { - type = "null"; - } else if ( typeof obj === "undefined" ) { - type = "undefined"; - } else if ( QUnit.is( "regexp", obj) ) { - type = "regexp"; - } else if ( QUnit.is( "date", obj) ) { - type = "date"; - } else if ( QUnit.is( "function", obj) ) { - type = "function"; - } else if ( typeof obj.setInterval !== undefined && typeof obj.document !== "undefined" && typeof obj.nodeType === "undefined" ) { - type = "window"; - } else if ( obj.nodeType === 9 ) { - type = "document"; - } else if ( obj.nodeType ) { - type = "node"; - } else if ( - // native arrays - toString.call( obj ) === "[object Array]" || - // NodeList objects - ( typeof obj.length === "number" && typeof obj.item !== "undefined" && ( obj.length ? obj.item(0) === obj[0] : ( obj.item( 0 ) === null && typeof obj[0] === "undefined" ) ) ) - ) { - type = "array"; - } else { - type = typeof obj; - } - return type; - }, - separator: function() { - return this.multiline ? this.HTML ? "
        " : "\n" : this.HTML ? " " : " "; - }, - indent: function( extra ) {// extra can be a number, shortcut for increasing-calling-decreasing - if ( !this.multiline ) { - return ""; - } - var chr = this.indentChar; - if ( this.HTML ) { - chr = chr.replace( /\t/g, " " ).replace( / /g, " " ); - } - return new Array( this._depth_ + (extra||0) ).join(chr); - }, - up: function( a ) { - this._depth_ += a || 1; - }, - down: function( a ) { - this._depth_ -= a || 1; - }, - setParser: function( name, parser ) { - this.parsers[name] = parser; - }, - // The next 3 are exposed so you can use them - quote: quote, - literal: literal, - join: join, - // - _depth_: 1, - // This is the list of parsers, to modify them, use jsDump.setParser - parsers: { - window: "[Window]", - document: "[Document]", - error: "[ERROR]", //when no parser is found, shouldn"t happen - unknown: "[Unknown]", - "null": "null", - "undefined": "undefined", - "function": function( fn ) { - var ret = "function", - name = "name" in fn ? fn.name : (reName.exec(fn) || [])[1];//functions never have name in IE - - if ( name ) { - ret += " " + name; - } - ret += "( "; - - ret = [ ret, QUnit.jsDump.parse( fn, "functionArgs" ), "){" ].join( "" ); - return join( ret, QUnit.jsDump.parse(fn,"functionCode" ), "}" ); - }, - array: array, - nodelist: array, - "arguments": array, - object: function( map, stack ) { - var ret = [ ], keys, key, val, i; - QUnit.jsDump.up(); - if ( Object.keys ) { - keys = Object.keys( map ); - } else { - keys = []; - for ( key in map ) { - keys.push( key ); - } - } - keys.sort(); - for ( i = 0; i < keys.length; i++ ) { - key = keys[ i ]; - val = map[ key ]; - ret.push( QUnit.jsDump.parse( key, "key" ) + ": " + QUnit.jsDump.parse( val, undefined, stack ) ); - } - QUnit.jsDump.down(); - return join( "{", ret, "}" ); - }, - node: function( node ) { - var a, val, - open = QUnit.jsDump.HTML ? "<" : "<", - close = QUnit.jsDump.HTML ? ">" : ">", - tag = node.nodeName.toLowerCase(), - ret = open + tag; - - for ( a in QUnit.jsDump.DOMAttrs ) { - val = node[ QUnit.jsDump.DOMAttrs[a] ]; - if ( val ) { - ret += " " + a + "=" + QUnit.jsDump.parse( val, "attribute" ); - } - } - return ret + close + open + "/" + tag + close; - }, - functionArgs: function( fn ) {//function calls it internally, it's the arguments part of the function - var args, - l = fn.length; - - if ( !l ) { - return ""; - } - - args = new Array(l); - while ( l-- ) { - args[l] = String.fromCharCode(97+l);//97 is 'a' - } - return " " + args.join( ", " ) + " "; - }, - key: quote, //object calls it internally, the key part of an item in a map - functionCode: "[code]", //function calls it internally, it's the content of the function - attribute: quote, //node calls it internally, it's an html attribute value - string: quote, - date: quote, - regexp: literal, //regex - number: literal, - "boolean": literal - }, - DOMAttrs: { - //attributes to dump from nodes, name=>realName - id: "id", - name: "name", - "class": "className" - }, - HTML: false,//if true, entities are escaped ( <, >, \t, space and \n ) - indentChar: " ",//indentation unit - multiline: true //if true, items in a collection, are separated by a \n, else just a space. - }; - - return jsDump; -}()); - -// from Sizzle.js -function getText( elems ) { - var i, elem, - ret = ""; - - for ( i = 0; elems[i]; i++ ) { - elem = elems[i]; - - // Get the text from text nodes and CDATA nodes - if ( elem.nodeType === 3 || elem.nodeType === 4 ) { - ret += elem.nodeValue; - - // Traverse everything else, except comment nodes - } else if ( elem.nodeType !== 8 ) { - ret += getText( elem.childNodes ); - } - } - - return ret; -} - -// from jquery.js -function inArray( elem, array ) { - if ( array.indexOf ) { - return array.indexOf( elem ); - } - - for ( var i = 0, length = array.length; i < length; i++ ) { - if ( array[ i ] === elem ) { - return i; - } - } - - return -1; -} - -/* - * Javascript Diff Algorithm - * By John Resig (http://ejohn.org/) - * Modified by Chu Alan "sprite" - * - * Released under the MIT license. - * - * More Info: - * http://ejohn.org/projects/javascript-diff-algorithm/ - * - * Usage: QUnit.diff(expected, actual) - * - * QUnit.diff( "the quick brown fox jumped over", "the quick fox jumps over" ) == "the quick brown fox jumped jumps over" - */ -QUnit.diff = (function() { - function diff( o, n ) { - var i, - ns = {}, - os = {}; - - for ( i = 0; i < n.length; i++ ) { - if ( ns[ n[i] ] == null ) { - ns[ n[i] ] = { - rows: [], - o: null - }; - } - ns[ n[i] ].rows.push( i ); - } - - for ( i = 0; i < o.length; i++ ) { - if ( os[ o[i] ] == null ) { - os[ o[i] ] = { - rows: [], - n: null - }; - } - os[ o[i] ].rows.push( i ); - } - - for ( i in ns ) { - if ( !hasOwn.call( ns, i ) ) { - continue; - } - if ( ns[i].rows.length == 1 && typeof os[i] != "undefined" && os[i].rows.length == 1 ) { - n[ ns[i].rows[0] ] = { - text: n[ ns[i].rows[0] ], - row: os[i].rows[0] - }; - o[ os[i].rows[0] ] = { - text: o[ os[i].rows[0] ], - row: ns[i].rows[0] - }; - } - } - - for ( i = 0; i < n.length - 1; i++ ) { - if ( n[i].text != null && n[ i + 1 ].text == null && n[i].row + 1 < o.length && o[ n[i].row + 1 ].text == null && - n[ i + 1 ] == o[ n[i].row + 1 ] ) { - - n[ i + 1 ] = { - text: n[ i + 1 ], - row: n[i].row + 1 - }; - o[ n[i].row + 1 ] = { - text: o[ n[i].row + 1 ], - row: i + 1 - }; - } - } - - for ( i = n.length - 1; i > 0; i-- ) { - if ( n[i].text != null && n[ i - 1 ].text == null && n[i].row > 0 && o[ n[i].row - 1 ].text == null && - n[ i - 1 ] == o[ n[i].row - 1 ]) { - - n[ i - 1 ] = { - text: n[ i - 1 ], - row: n[i].row - 1 - }; - o[ n[i].row - 1 ] = { - text: o[ n[i].row - 1 ], - row: i - 1 - }; - } - } - - return { - o: o, - n: n - }; - } - - return function( o, n ) { - o = o.replace( /\s+$/, "" ); - n = n.replace( /\s+$/, "" ); - - var i, pre, - str = "", - out = diff( o === "" ? [] : o.split(/\s+/), n === "" ? [] : n.split(/\s+/) ), - oSpace = o.match(/\s+/g), - nSpace = n.match(/\s+/g); - - if ( oSpace == null ) { - oSpace = [ " " ]; - } - else { - oSpace.push( " " ); - } - - if ( nSpace == null ) { - nSpace = [ " " ]; - } - else { - nSpace.push( " " ); - } - - if ( out.n.length === 0 ) { - for ( i = 0; i < out.o.length; i++ ) { - str += "" + out.o[i] + oSpace[i] + ""; - } - } - else { - if ( out.n[0].text == null ) { - for ( n = 0; n < out.o.length && out.o[n].text == null; n++ ) { - str += "" + out.o[n] + oSpace[n] + ""; - } - } - - for ( i = 0; i < out.n.length; i++ ) { - if (out.n[i].text == null) { - str += "" + out.n[i] + nSpace[i] + ""; - } - else { - // `pre` initialized at top of scope - pre = ""; - - for ( n = out.n[i].row + 1; n < out.o.length && out.o[n].text == null; n++ ) { - pre += "" + out.o[n] + oSpace[n] + ""; - } - str += " " + out.n[i].text + nSpace[i] + pre; - } - } - } - - return str; - }; -}()); - -// for CommonJS enviroments, export everything -if ( typeof exports !== "undefined" ) { - extend(exports, QUnit); -} - -// get at whatever the global object is, like window in browsers -}( (function() {return this;}.call()) )); diff --git a/test/table.js b/test/table.js new file mode 100644 index 0000000..501b829 --- /dev/null +++ b/test/table.js @@ -0,0 +1,421 @@ +// table.yml +import test from 'ava'; +import textile from '../src'; + +test( 'table:1', function ( t ) { + let tx = "|a|b|c|\n\ +|1|2|3|\n\n\ +h3. A header after the table"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        abc
        123
        \n\ +

        A header after the table

        ", tx ); +}); + + +test( 'table:2', function ( t ) { + let tx = "|_. a|_. b|_. c|\n\ +|1|2|3|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        abc
        123
        ", tx ); +}); + + +test( 'table:3', function ( t ) { + let tx = "|This|is|a|simple|table|\n\ +|This|is|a|simple|row|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        Thisisasimpletable
        Thisisasimplerow
        ", tx ); +}); + + +test( 'table:4', function ( t ) { + let tx = "table{border:1px solid black}.\n\ +|This|is|a|row|\n\ +|This|is|a|row|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        Thisisarow
        Thisisarow
        ", tx ); +}); + + +test( 'table:5', function ( t ) { + let tx = "{background:#ddd}. |This|is|a|row|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        Thisisarow
        ", tx ); +}); + + +test( 'table:6', function ( t ) { + let tx = "|a|b|c|\n\ +| |2|3|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        abc
        23
        ", tx ); +}); + + +test( 'table:7', function ( t ) { + let tx = "table{width: 200px; border:2px solid gray;}.\n\ +|_=. Alignment|\n\ +|=. centered|\n\ +|=(. a bit right|\n\ +|=). a bit left|\n\ +|>). almost right|\n\ +|<(. almost left|\n\ +|>. right|\n\ +|<. left|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +
        Alignment
        centered
        a bit right
        a bit left
        almost right
        almost left
        right
        left
        ", tx ); +}); + + +test( 'table:8', function ( t ) { + let tx = "|{background:#ddd}. Cell with gray background|Normal cell|\n\ +|\\2. Cell spanning 2 columns|\n\ +|/2. Cell spanning 2 rows|one|\n\ +|two|\n\ +|>. Right-aligned cell|<. Left-aligned cell|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        Cell with gray backgroundNormal cell
        Cell spanning 2 columns
        Cell spanning 2 rowsone
        two
        Right-aligned cellLeft-aligned cell
        ", tx ); +}); + + +test( 'row spanning mid-row', function ( t ) { + let tx = "|1|2|3|\n\ +|1|/3. 2|3|\n\ +|1|3|\n\ +|1|3|\n\ +|1|2|3|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        123
        123
        13
        13
        123
        ", tx ); +}); + + +test( 'table:10', function ( t ) { + let tx = "{background:#ddd}. |S|Target|Complete|App|Milestone|\n\ +|!/i/g.gif!|11/29/04|11/29/04|011|XML spec complete (KH is on schedule)|\n\ +|!/i/g.gif!|11/22/04|11/22/04|070|Dialog pass 1 builds an index file|\n\ +|!/i/g.gif!|11/24/04|11/24/04|070|Dialog pass 2 98% complete|\n\ +|!/i/g.gif!|11/30/04|11/30/04|070|Feature complete. Passes end-to-end smoke test.|\n\ +|!/i/w.gif!|12/02/04| |011|Dialog pass 1 and 2 complete (98+%)|\n\ +|!/i/w.gif!|12/03/04| |081|Feature complete|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        STargetCompleteAppMilestone
        \"\"11/29/0411/29/04011XML spec complete (KH is on schedule)
        \"\"11/22/0411/22/04070Dialog pass 1 builds an index file
        \"\"11/24/0411/24/04070Dialog pass 2 98% complete
        \"\"11/30/0411/30/04070Feature complete. Passes end-to-end smoke test.
        \"\"12/02/04 011Dialog pass 1 and 2 complete (98+%)
        \"\"12/03/04 081Feature complete
        ", tx ); +}); + + +test( 'combined table header and colspan', function ( t ) { + let tx = "table(my_class).\n\ +|_\\2. a |_. b |_. c |\n\ +| 1 | 2 | 3 | 4 |"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        a b c
        1 2 3 4
        ", tx ); +}); + + +test( 'two adjacent tables', function ( t ) { + let tx = "|a|b|c|\n\n\ +|1|2|3|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        abc
        \n\ +\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        123
        ", tx ); +}); + + +test( 'with cell attributes', function ( t ) { + let tx = "|[en]. lang-ok|{color:red;}. style-ok|(myclass). class-ok|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        lang-okstyle-okclass-ok
        ", tx ); +}); + + +test( 'with improper cell attributes', function ( t ) { + let tx = "|[en]lang-bad|{color:red;}style-bad|(myclass)class-bad|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        [en]lang-bad{color:red;}style-bad(myclass)class-bad
        ", tx ); +}); + + +test( 'with line breaks in the cell', function ( t ) { + let tx = "|a|b\n\ +b|\n\ +|c\n\ +c|d|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        ab
        \n\ +b
        c
        \n\ +c
        d
        ", tx ); +}); + + +test( 'with missing cells', function ( t ) { + let tx = "|a|b|\n\ +|a|\n\ +|a|b|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        ab
        a
        ab
        ", tx ); +}); + + +test( 'with empty cells', function ( t ) { + let tx = "||b|\n\ +|a||\n\ +|a| |"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        b
        a
        a
        ", tx ); +}); + diff --git a/test/tables-extended.js b/test/tables-extended.js index 5b6f880..135c9c2 100644 --- a/test/tables-extended.js +++ b/test/tables-extended.js @@ -1,14 +1,12 @@ -test('extened table syntax', function () { - - -equal(textile.convert( // the textile - -"|_. First Header |_. Second Header |\n\ -| Content Cell | Content Cell |" - -), // Should output - -"\n\ +// extened table syntax +import test from 'ava'; +import textile from '../src'; + +test( 'headers and cells', function ( t ) { + let tx = "|_. First Header |_. Second Header |\n\ +| Content Cell | Content Cell |"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\t\n\ @@ -17,20 +15,15 @@ equal(textile.convert( // the textile \t\t\n\ \t\t\n\ \t\n\ -
        First Header Second Header Content Cell Content Cell
        " - -, "headers and cells"); - - - -equal(textile.convert( - -"|=. Your caption goes here\n\ -|foo|bar|" +
      1. ", tx ); +}); -), // Should output -"\n\ +test( 'captions', function ( t ) { + let tx = "|=. Your caption goes here\n\ +|foo|bar|"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\n\ \t\t\n\ @@ -38,22 +31,17 @@ equal(textile.convert( \t\t\t\n\ \t\t\n\ \t\n\ -
        Your caption goes here
        bar
        " - -, "captions"); - +

      2. ", tx ); +}); -equal(textile.convert( // the textile -"|=. caption |\n\ -| foo |\n\ -\n\ +test( 'tailing pipes should be stripped from captions', function ( t ) { + let tx = "|=. caption |\n\ +| foo |\n\n\ |=. caption\n\ -| foo |" - -), // Should output - -"\n\ +| foo |"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\n\ \t\t\n\ @@ -68,40 +56,31 @@ equal(textile.convert( // the textile \t\t\t\n\ \t\t\n\ \t\n\ -
        caption
        foo
        " - -, "tailing pipes should be stripped from captions"); - - -equal(textile.convert( // the textile - -"table(myTable). This is a journey into sound. Stereophonic sound.\n\ -| foo |" +

      3. ", tx ); +}); -), // Should output -"\n\ +test( 'table summary', function ( t ) { + let tx = "table(myTable). This is a journey into sound. Stereophonic sound.\n\ +| foo |"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\n\ -
        foo
        " - -, "table summary"); - - +

      4. ", tx ); +}); -equal(textile.convert( // the textile -"|^.\n\ +test( 'tbody/thead/tfoot', function ( t ) { + let tx = "|^.\n\ |in head|\n\ |~.\n\ |in foot|\n\ |-.\n\ -|in body|" - -), // Should output - -"\n\ +|in body|"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\t\t\n\ @@ -117,19 +96,15 @@ equal(textile.convert( // the textile \t\t\t\n\ \t\t\n\ \t\n\ -
        in headin body
        " - -, "tbody/thead/tfoot"); - - -equal(textile.convert( // the textile - -"|:. 100|\n\ -|cell|" +

      5. ", tx ); +}); -), // Should output -"\n\ +test( 'colgroup', function ( t ) { + let tx = "|:. 100|\n\ +|cell|"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\n\ \t\n\ @@ -137,19 +112,15 @@ equal(textile.convert( // the textile \t\t\t\n\ \t\t\n\ \t\n\ -
        cell
        " - -, "colgroup"); - - -equal(textile.convert( // the textile - -"|:\\3. 100|\n\ -|cell|" +

      6. ", tx ); +}); -), // Should output -"\n\ +test( 'colgroup span size', function ( t ) { + let tx = "|:\\3. 100|\n\ +|cell|"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\n\ \t\n\ @@ -157,19 +128,15 @@ equal(textile.convert( // the textile \t\t\t\n\ \t\t\n\ \t\n\ -
        cell
        " - -, "colgroup span size"); - - -equal(textile.convert( // the textile - -"|:. |\\2. |\\3. 50|\n\ -|cell|cell|" +", tx ); +}); -), // Should output -"\n\ +test( 'can target individual cols', function ( t ) { + let tx = "|:. |\\2. |\\3. 50|\n\ +|cell|cell|"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\t\n\ @@ -180,19 +147,15 @@ equal(textile.convert( // the textile \t\t\t\n\ \t\t\n\ \t\n\ -
        cell
        " - -, "can target individual cols"); - - -equal(textile.convert( // the textile - -"|:\\5(grpclass#grpid). 200 | 100 |||80|\n\ -|cell|cell|" +", tx ); +}); -), // Should output -"\n\ +test( 'can style colgroup', function ( t ) { + let tx = "|:\\5(grpclass#grpid). 200 | 100 |||80|\n\ +|cell|cell|"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\t\n\ @@ -205,23 +168,18 @@ equal(textile.convert( // the textile \t\t\t\n\ \t\t\n\ \t\n\ -
        cell
        " - -, "can style colgroup"); - - +", tx ); +}); -equal(textile.convert( // the textile -"|^.\n\ +test( 'extened table syntax:10', function ( t ) { + let tx = "|^.\n\ |_. First Header |_. Second Header |\n\ |-.\n\ | Content Cell | Content Cell |\n\ -| Content Cell | Content Cell |" - -), // Should output - -"\n\ +| Content Cell | Content Cell |"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\t\t\n\ @@ -238,23 +196,19 @@ equal(textile.convert( // the textile \t\t\t\n\ \t\t\n\ \t\n\ -
        First Header Content Cell
        " - -, ""); - +", tx ); +}); -equal(textile.convert( // the textile -"|~.\n\ +test( 'extened table syntax:11', function ( t ) { + let tx = "|~.\n\ |\\2=. A footer, centered & across two columns |\n\ |-.\n\ | Content Cell | Content Cell |\n\ | Content Cell | Content Cell |\n\ -" - -), // Should output - -"\n\ +"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\t\t\n\ @@ -270,56 +224,43 @@ equal(textile.convert( // the textile \t\t\t\n\ \t\t\n\ \t\n\ -
        A footer, centered & across two columns Content Cell
        " - -, ""); - - - -equal(textile.convert( // the textile - -"|a|{color:red}. styled|cell|\n\ -" +", tx ); +}); -), // Should output -"\n\ +test( 'styleable cells', function ( t ) { + let tx = "|a|{color:red}. styled|cell|\n\ +"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\t\n\ \t\t\n\ \t\n\ -
        astyledcell
        " - -, "styleable cells"); - - -equal(textile.convert( // the textile - -"(rowclass). |a|classy|row|" +", tx ); +}); -), // Should output -"\n\ +test( 'row class', function ( t ) { + let tx = "(rowclass). |a|classy|row|"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\t\n\ \t\t\n\ \t\n\ -
        aclassyrow
        " - -, "row class"); - +", tx ); +}); -equal(textile.convert( // the textile -"table(tableclass).\n\ +test( 'table class', function ( t ) { + let tx = "table(tableclass).\n\ |a|classy|table|\n\ -|a|classy|table|" - -), // Should output - -"\n\ +|a|classy|table|"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\t\n\ @@ -330,19 +271,15 @@ equal(textile.convert( // the textile \t\t\n\ \t\t\n\ \t\n\ -
        aclassyclassytable
        " - -, "table class"); - - -equal(textile.convert( // the textile - -"|\\2. spans two cols |\n\ -| col 1 | col 2 |" +", tx ); +}); -), // Should output -"\n\ +test( 'column span', function ( t ) { + let tx = "|\\2. spans two cols |\n\ +| col 1 | col 2 |"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\n\ @@ -350,20 +287,16 @@ equal(textile.convert( // the textile \t\t\n\ \t\t\n\ \t\n\ -
        spans two cols
        col 1 col 2
        " - -, "column span"); - +", tx ); +}); -equal(textile.convert( // the textile -"|/3. spans 3 rows | row a |\n\ +test( 'row span', function ( t ) { + let tx = "|/3. spans 3 rows | row a |\n\ | row b |\n\ -| row c |" - -), // Should output - -"\n\ +| row c |"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\t\n\ @@ -374,19 +307,16 @@ equal(textile.convert( // the textile \t\n\ \t\t\n\ \t\n\ -
        spans 3 rows row a
        row c
        " - -, "row span"); +", tx ); +}); -equal(textile.convert( // the textile -"|^. top alignment|\n\ +test( 'cell text v-alignment', function ( t ) { + let tx = "|^. top alignment|\n\ |-. middle alignment|\n\ -|~. bottom alignment|" - -), // Should output - -"\n\ +|~. bottom alignment|"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\n\ @@ -396,21 +326,17 @@ equal(textile.convert( // the textile \t\n\ \t\t\n\ \t\n\ -
        top alignment
        bottom alignment
        " - -, "cell text v-alignment"); - +", tx ); +}); -equal(textile.convert( // the textile -"|:\\1. |400|\n\ +test( 'cell text h-alignment', function ( t ) { + let tx = "|:\\1. |400|\n\ |=. center alignment |\n\ | no alignment |\n\ -|>. right alignment |" - -), // Should output - -"\n\ +|>. right alignment |"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\n\ @@ -425,15 +351,12 @@ equal(textile.convert( // the textile \t\t\t\n\ \t\t\n\ \t\n\ -
        right alignment
        " - -, "cell text h-alignment"); - +", tx ); +}); -equal(textile.convert( // the textile -"p=. Full table with summary, caption, colgroups, thead, tfoot, 2x tbody\n\ -\n\ +test( 'a complex table example', function ( t ) { + let tx = "p=. Full table with summary, caption, colgroups, thead, tfoot, 2x tbody\n\n\ table(#dvds){border-collapse:collapse}. Great films on DVD employing Textile summary, caption, thead, tfoot, two tbody elements and colgroups\n\ |={font-size:140%;margin-bottom:15px}. DVDs with two Textiled tbody elements\n\ |:\\3. 100 |{background:#ddd}|250||50|300|\n\ @@ -448,11 +371,9 @@ table(#dvds){border-collapse:collapse}. Great films on DVD employing Textile sum | _District 9_ | Sharlto Copley, Jason Cope | Neill Blomkamp | Neill Blomkamp, Terri Tatchell | Social commentary layered on thick, but boy is it done well |\n\ |-(medlist){background:#e7e895;}.\n\ | _Arlington Road_ | Tim Robbins, Jeff Bridges | Mark Pellington | Ehren Kruger | Awesome study in neighbourly relations |\n\ -| _Phone Booth_ | Colin Farrell, Kiefer Sutherland, Forest Whitaker | Joel Schumacher | Larry Cohen | Edge-of-the-seat stuff in this short but brilliantly executed thriller |" - -), // Should output - -"

        Full table with summary, caption, colgroups, thead, tfoot, 2x tbody

        \n\ +| _Phone Booth_ | Colin Farrell, Kiefer Sutherland, Forest Whitaker | Joel Schumacher | Larry Cohen | Edge-of-the-seat stuff in this short but brilliantly executed thriller |"; + t.is( textile.convert( tx ), + "

        Full table with summary, caption, colgroups, thead, tfoot, 2x tbody

        \n\ \n\ \t\n\ \t\n\ @@ -522,15 +443,12 @@ table(#dvds){border-collapse:collapse}. Great films on DVD employing Textile sum \t\t\t\n\ \t\t\n\ \t\n\ -
        DVDs with two Textiled tbody elements
        Edge-of-the-seat stuff in this short but brilliantly executed thriller
        " - -, "a complex table example"); - - +", tx ); +}); -equal(textile.convert( // the textile -"table(tabl).\n\ +test( 'attr can be passed to all the containers', function ( t ) { + let tx = "table(tabl).\n\ |=(cap#id1). caption\n\ |:(colgr#id2). |\n\ |^(head#id3).\n\ @@ -538,11 +456,9 @@ equal(textile.convert( // the textile |-(body#id4).\n\ | a | b |\n\ |~(foot#id5).\n\ -| c | d |" - -), // Should output - -"\n\ +| c | d |"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\n\ \t\n\ @@ -564,21 +480,16 @@ equal(textile.convert( // the textile \t\t\t\n\ \t\t\n\ \t\n\ -
        caption
        d
        " - -, "attr can be passed to all the containers"); - - +", tx ); +}); -equal(textile.convert( // the textile -"table(tabl).\n\ +test( 'classes on cols', function ( t ) { + let tx = "table(tabl).\n\ |:(colgr#id2). |\\2(class#id) 20 |\n\ -| a | b |" - -), // Should output - -"\n\ +| a | b |"; + t.is( textile.convert( tx ), + "
        \n\ \t\n\ \t\t\n\ \t\n\ @@ -588,10 +499,6 @@ equal(textile.convert( // the textile \t\t\t\n\ \t\t\n\ \t\n\ -
        b
        " - -, "classes on cols"); - - - +", tx ); }); + diff --git a/test/textism.js b/test/textism.js new file mode 100644 index 0000000..5d65694 --- /dev/null +++ b/test/textism.js @@ -0,0 +1,390 @@ +// textism.yml +import test from 'ava'; +import textile from '../src'; + +test( 'header one', function ( t ) { + let tx = "h1. Header 1"; + t.is( textile.convert( tx ), + "

        Header 1

        ", tx ); +}); + + +test( 'header two', function ( t ) { + let tx = "h2. Header 2"; + t.is( textile.convert( tx ), + "

        Header 2

        ", tx ); +}); + + +test( 'header three', function ( t ) { + let tx = "h3. Header 3"; + t.is( textile.convert( tx ), + "

        Header 3

        ", tx ); +}); + + +test( 'header four', function ( t ) { + let tx = "h4. Header 4"; + t.is( textile.convert( tx ), + "

        Header 4

        ", tx ); +}); + + +test( 'header five', function ( t ) { + let tx = "h5. Header 5"; + t.is( textile.convert( tx ), + "
        Header 5
        ", tx ); +}); + + +test( 'header six', function ( t ) { + let tx = "h6. Header 6"; + t.is( textile.convert( tx ), + "
        Header 6
        ", tx ); +}); + + +test( 'blockquote', function ( t ) { + let tx = "Any old text.\n\n\ +bq. A block quotation.\n\n\ +Any old text.\n\ +"; + t.is( textile.convert( tx ), + "

        Any old text.

        \n\ +
        \n\ +

        A block quotation.

        \n\ +
        \n\ +

        Any old text.

        ", tx ); +}); + + +test( 'textism:8', function ( t ) { + let tx = "# A first item\n\ +# A second item\n\ +# A third item\n\ +# A fourth item"; + t.is( textile.convert( tx ), + "
          \n\ +\t
        1. A first item
        2. \n\ +\t
        3. A second item
        4. \n\ +\t
        5. A third item
        6. \n\ +\t
        7. A fourth item
        8. \n\ +
        ", tx ); +}); + + +test( 'textism:9', function ( t ) { + let tx = "* A first item\n\ +* A second item\n\ +* A third item\n\ +* A fourth item\n\ +"; + t.is( textile.convert( tx ), + "", tx ); +}); + + +test( 'textism:10', function ( t ) { + let tx = "_a phrase_"; + t.is( textile.convert( tx ), + "

        a phrase

        ", tx ); +}); + + +test( 'textism:11', function ( t ) { + let tx = "__a phrase__"; + t.is( textile.convert( tx ), + "

        a phrase

        ", tx ); +}); + + +test( 'textism:12', function ( t ) { + let tx = "*a phrase*"; + t.is( textile.convert( tx ), + "

        a phrase

        ", tx ); +}); + + +test( 'textism:13', function ( t ) { + let tx = "**a phrase**"; + t.is( textile.convert( tx ), + "

        a phrase

        ", tx ); +}); + + +test( 'textism:14', function ( t ) { + let tx = "Nabokov's ??Pnin??"; + t.is( textile.convert( tx ), + "

        Nabokov’s Pnin

        ", tx ); +}); + + +test( 'del part of word', function ( t ) { + let tx = "A very [-extra-]ordinary day."; + t.is( textile.convert( tx ), + "

        A very extraordinary day.

        ", tx ); +}); + + +test( 'del part of word that contains a hyphen', function ( t ) { + let tx = "An [-extra-extra-]ordinary day."; + t.is( textile.convert( tx ), + "

        An extra-extraordinary day.

        ", tx ); +}); + + +test( 'del a phrase', function ( t ) { + let tx = "Delete -a phrase- this way."; + t.is( textile.convert( tx ), + "

        Delete a phrase this way.

        ", tx ); +}); + + +test( 'del a phrase that contains hyphens', function ( t ) { + let tx = "Delete -a no-nonsense phrase- this way."; + t.is( textile.convert( tx ), + "

        Delete a no-nonsense phrase this way.

        ", tx ); +}); + + +test( 'textism:19', function ( t ) { + let tx = "+a phrase+"; + t.is( textile.convert( tx ), + "

        a phrase

        ", tx ); +}); + + +test( 'textism:20', function ( t ) { + let tx = "^a phrase^"; + t.is( textile.convert( tx ), + "

        a phrase

        ", tx ); +}); + + +test( 'textism:21', function ( t ) { + let tx = "~a phrase~"; + t.is( textile.convert( tx ), + "

        a phrase

        ", tx ); +}); + + +test( 'textism:22', function ( t ) { + let tx = "%(myclass)SPAN%"; + t.is( textile.convert( tx ), + "

        SPAN

        ", tx ); +}); + + +test( 'textism:23', function ( t ) { + let tx = "%{color:red}red%"; + t.is( textile.convert( tx ), + "

        red

        ", tx ); +}); + + +test( 'textism:24', function ( t ) { + let tx = "%[fr]rouge%"; + t.is( textile.convert( tx ), + "

        rouge

        ", tx ); +}); + + +test( 'textism:25', function ( t ) { + let tx = "_(big)red_"; + t.is( textile.convert( tx ), + "

        red

        ", tx ); +}); + + +test( 'textism:26', function ( t ) { + let tx = "p=. A centered paragraph."; + t.is( textile.convert( tx ), + "

        A centered paragraph.

        ", tx ); +}); + + +test( 'textism:27', function ( t ) { + let tx = "p(bob). A paragraph"; + t.is( textile.convert( tx ), + "

        A paragraph

        ", tx ); +}); + + +test( 'textism:28', function ( t ) { + let tx = "p{color:#ddd}. A paragraph"; + t.is( textile.convert( tx ), + "

        A paragraph

        ", tx ); +}); + + +test( 'textism:29', function ( t ) { + let tx = "p[fr]. A paragraph"; + t.is( textile.convert( tx ), + "

        A paragraph

        ", tx ); +}); + + +test( 'textism:30', function ( t ) { + let tx = "h2()>. right-aligned header2, indented 1em both side"; + t.is( textile.convert( tx ), + "

        right-aligned header2, indented 1em both side

        ", tx ); +}); + + +test( 'textism:31', function ( t ) { + let tx = "h3=. centered header"; + t.is( textile.convert( tx ), + "

        centered header

        ", tx ); +}); + + +test( 'textism:32', function ( t ) { + let tx = "!>/image.gif! right-aligned image"; + t.is( textile.convert( tx ), + "

        \"\" right-aligned image

        ", tx ); +}); + + +test( 'textism:33', function ( t ) { + let tx = "p[no]{color:red}. A Norse of a different colour."; + t.is( textile.convert( tx ), + "

        A Norse of a different colour.

        ", tx ); +}); + + +test( 'textism:34', function ( t ) { + let tx = "|This|is|a|simple|table|\n\ +|This|is|a|simple|row|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        Thisisasimpletable
        Thisisasimplerow
        ", tx ); +}); + + +test( 'textism:35', function ( t ) { + let tx = "table{border:1px solid black}.\n\ +|This|is|a|row|\n\ +|This|is|a|row|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        Thisisarow
        Thisisarow
        ", tx ); +}); + + +test( 'textism:36', function ( t ) { + let tx = "{background:#ddd}. |This|is|a|row|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        Thisisarow
        ", tx ); +}); + + +test( 'textism:37', function ( t ) { + let tx = "|{background:#ddd}. Cell with gray background|\n\ +|\\2. Cell spanning 2 columns|\n\ +|/3. Cell spanning 3 rows|\n\ +|>. Right-aligned cell|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +
        Cell with gray background
        Cell spanning 2 columns
        Cell spanning 3 rows
        Right-aligned cell
        ", tx ); +}); + + +test( 'basics', function ( t ) { + let tx = "h2{color:green}. This is a title\n\n\ +h3. This is a subhead\n\n\ +p{color:red}. This is some text of dubious character. Isn't the use of \"quotes\" just lazy writing -- and theft of 'intellectual property' besides? I think the time has come to see a block quote.\n\n\ +bq[fr]. This is a block quote. I'll admit it's not the most exciting block quote ever devised.\n\n\ +Simple list:\n\n\ +# one\n\ +# two\n\ +# three\n\n\ +Multi-level list:\n\n\ +# one\n\ +## aye\n\ +## bee\n\ +## see\n\ +# two\n\ +## x\n\ +## y\n\ +# three\n\ +"; + t.is( textile.convert( tx ), + "

        This is a title

        \n\ +

        This is a subhead

        \n\ +

        This is some text of dubious character. Isn’t the use of “quotes” just lazy writing — and theft of ‘intellectual property’ besides? I think the time has come to see a block quote.

        \n\ +
        \n\ +

        This is a block quote. I’ll admit it’s not the most exciting block quote ever devised.

        \n\ +
        \n\ +

        Simple list:

        \n\ +
          \n\ +\t
        1. one
        2. \n\ +\t
        3. two
        4. \n\ +\t
        5. three
        6. \n\ +
        \n\ +

        Multi-level list:

        \n\ +
          \n\ +\t
        1. one\n\ +\t
            \n\ +\t\t
          1. aye
          2. \n\ +\t\t
          3. bee
          4. \n\ +\t\t
          5. see
          6. \n\ +\t
        2. \n\ +\t
        3. two\n\ +\t
            \n\ +\t\t
          1. x
          2. \n\ +\t\t
          3. y
          4. \n\ +\t
        4. \n\ +\t
        5. three
        6. \n\ +
        ", tx ); +}); + diff --git a/test/threshold.js b/test/threshold.js new file mode 100644 index 0000000..4dd55de --- /dev/null +++ b/test/threshold.js @@ -0,0 +1,870 @@ +// threshold.yml +import test from 'ava'; +import textile from '../src'; + +test( 'paragraph', function ( t ) { + let tx = "A paragraph.\n\n\ +Another paragraph."; + t.is( textile.convert( tx ), + "

        A paragraph.

        \n\ +

        Another paragraph.

        ", tx ); +}); + + +test( 'line breaks', function ( t ) { + let tx = "A paragraph with\n\ +a line break."; + t.is( textile.convert( tx ), + "

        A paragraph with
        \n\ +a line break.

        ", tx ); +}); + + +test( 'xhtml tags', function ( t ) { + let tx = "Here's some bold text."; + t.is( textile.convert( tx ), + "

        Here’s some bold text.

        ", tx ); +}); + + +test( 'no paragraph tags', function ( t ) { + let tx = " No paragraph tags here."; + t.is( textile.convert( tx ), + "No paragraph tags here.", tx ); +}); + + +test( 'smart quotes', function ( t ) { + let tx = "\"Proceed!\" said he to the host."; + t.is( textile.convert( tx ), + "

        “Proceed!” said he to the host.

        ", tx ); +}); + + +test( 'smart quotes 2', function ( t ) { + let tx = "'Proceed!' said he to the host."; + t.is( textile.convert( tx ), + "

        ‘Proceed!’ said he to the host.

        ", tx ); +}); + + +test( 'nested quotation marks', function ( t ) { + let tx = "\"'I swear, captain,' replied I.\""; + t.is( textile.convert( tx ), + "

        “‘I swear, captain,’ replied I.”

        ", tx ); +}); + + +test( 'nested quotation marks 2', function ( t ) { + let tx = "'\"I swear, captain,\" replied I.'"; + t.is( textile.convert( tx ), + "

        ‘“I swear, captain,” replied I.’

        ", tx ); +}); + + +test( 'apostrophe glyphs', function ( t ) { + let tx = "Greengrocers' apostrophe's."; + t.is( textile.convert( tx ), + "

        Greengrocers’ apostrophe’s.

        ", tx ); +}); + + +test( 'em-dash glyphs', function ( t ) { + let tx = "You know the Italian proverb -- Chi ha compagno ha padrone."; + t.is( textile.convert( tx ), + "

        You know the Italian proverb — Chi ha compagno ha padrone.

        ", tx ); +}); + + +test( 'em-dash glyphs 2', function ( t ) { + let tx = "You know the Italian proverb--Chi ha compagno ha padrone."; + t.is( textile.convert( tx ), + "

        You know the Italian proverb—Chi ha compagno ha padrone.

        ", tx ); +}); + + +test( 'en-dash glyphs', function ( t ) { + let tx = "You know the Italian proverb - Chi ha compagno ha padrone."; + t.is( textile.convert( tx ), + "

        You know the Italian proverb – Chi ha compagno ha padrone.

        ", tx ); +}); + + +test( 'ellipsis character', function ( t ) { + let tx = "Meanwhile..."; + t.is( textile.convert( tx ), + "

        Meanwhile…

        ", tx ); +}); + + +test( 'dimension character', function ( t ) { + let tx = "1 x 2 x 3 = 6"; + t.is( textile.convert( tx ), + "

        1 × 2 × 3 = 6

        ", tx ); +}); + + +test( 'dimension character 2', function ( t ) { + let tx = "1x2x3 = 6"; + t.is( textile.convert( tx ), + "

        1×2×3 = 6

        ", tx ); +}); + + +test( 'trademark register copyright', function ( t ) { + let tx = "Registered(r) Trademark(tm) Copyright (c)."; + t.is( textile.convert( tx ), + "

        Registered® Trademark™ Copyright ©.

        ", tx ); +}); + + +test( 'acronyms', function ( t ) { + let tx = "ABC(Always Be Closing)"; + t.is( textile.convert( tx ), + "

        ABC

        ", tx ); +}); + + +test( 'uppercase', function ( t ) { + let tx = "IBM or HAL"; + t.is( textile.convert( tx ), + "

        IBM or HAL

        ", tx ); +}); + + +test( 'emphasis', function ( t ) { + let tx = "The _underlying_ cause."; + t.is( textile.convert( tx ), + "

        The underlying cause.

        ", tx ); +}); + + +test( 'strong text', function ( t ) { + let tx = "The *underlying* cause."; + t.is( textile.convert( tx ), + "

        The underlying cause.

        ", tx ); +}); + + +test( 'italic text', function ( t ) { + let tx = "The __underlying__ cause."; + t.is( textile.convert( tx ), + "

        The underlying cause.

        ", tx ); +}); + + +test( 'bold text', function ( t ) { + let tx = "The **underlying** cause."; + t.is( textile.convert( tx ), + "

        The underlying cause.

        ", tx ); +}); + + +test( 'citation', function ( t ) { + let tx = "??The Count of Monte Cristo??, by Dumas."; + t.is( textile.convert( tx ), + "

        The Count of Monte Cristo, by Dumas.

        ", tx ); +}); + + +test( 'inserted and deleted text', function ( t ) { + let tx = "Scratch -that-, replace with +this+."; + t.is( textile.convert( tx ), + "

        Scratch that, replace with this.

        ", tx ); +}); + + +test( 'subscript', function ( t ) { + let tx = "log ~2~ n"; + t.is( textile.convert( tx ), + "

        log 2 n

        ", tx ); +}); + + +test( 'superscript', function ( t ) { + let tx = "2 ^x^"; + t.is( textile.convert( tx ), + "

        2 x

        ", tx ); +}); + + +test( 'span tag', function ( t ) { + let tx = "The %underlying% cause."; + t.is( textile.convert( tx ), + "

        The underlying cause.

        ", tx ); +}); + + +test( 'code', function ( t ) { + let tx = "About the @
        @ tag."; + t.is( textile.convert( tx ), + "

        About the <hr /> tag.

        ", tx ); +}); + + +test( 'links', function ( t ) { + let tx = "\"link text\":http://example.com/"; + t.is( textile.convert( tx ), + "

        link text

        ", tx ); +}); + + +test( 'local links', function ( t ) { + let tx = "\"link text\":/example"; + t.is( textile.convert( tx ), + "

        link text

        ", tx ); +}); + + +test( 'link title', function ( t ) { + let tx = "\"link text(with title)\":http://example.com/"; + t.is( textile.convert( tx ), + "

        link text

        ", tx ); +}); + + +test( 'link alias', function ( t ) { + let tx = "Here's \"a link\":tstate, and\n\ +\"another link\":tstate to the same site.\n\n\ +[tstate]http://thresholdstate.com/"; + t.is( textile.convert( tx ), + "

        Here’s a link, and
        \n\ +another link to the same site.

        ", tx ); +}); + + +test( 'image', function ( t ) { + let tx = "!/img.gif!"; + t.is( textile.convert( tx ), + "

        \"\"

        ", tx ); +}); + + +test( 'image 2', function ( t ) { + let tx = "!http://thresholdstate.com/img.gif!"; + t.is( textile.convert( tx ), + "

        \"\"

        ", tx ); +}); + + +test( 'image alt', function ( t ) { + let tx = "!/img.gif(alt text)!"; + t.is( textile.convert( tx ), + "

        \"alt

        ", tx ); +}); + + +test( 'image links', function ( t ) { + let tx = "!/img.gif!:http://textpattern.com/"; + t.is( textile.convert( tx ), + "

        \"\"

        ", tx ); +}); + + +test( 'headers', function ( t ) { + let tx = "h1. Heading 1"; + t.is( textile.convert( tx ), + "

        Heading 1

        ", tx ); +}); + + +test( 'headers 2', function ( t ) { + let tx = "h2. Heading 2"; + t.is( textile.convert( tx ), + "

        Heading 2

        ", tx ); +}); + + +test( 'headers 3', function ( t ) { + let tx = "h6. Heading 6"; + t.is( textile.convert( tx ), + "
        Heading 6
        ", tx ); +}); + + +test( 'paragraph text', function ( t ) { + let tx = "p. A paragraph.\n\ +Continued.\n\n\ +Also a paragraph."; + t.is( textile.convert( tx ), + "

        A paragraph.
        \n\ +Continued.

        \n\ +

        Also a paragraph.

        ", tx ); +}); + + +test( 'block quote', function ( t ) { + let tx = "bq. A quotation.\n\ +Continued.\n\n\ +Regular paragraph."; + t.is( textile.convert( tx ), + "
        \n\ +

        A quotation.
        \n\ +Continued.

        \n\ +
        \n\ +

        Regular paragraph.

        ", tx ); +}); + + +test( 'block quote citation', function ( t ) { + let tx = "bq.:http://thresholdstate.com/ A cited quotation."; + t.is( textile.convert( tx ), + "
        \n\ +

        A cited quotation.

        \n\ +
        ", tx ); +}); + + +test( 'footnotes', function ( t ) { + let tx = "A footnote reference[1].\n\n\ +fn1. The footnote."; + t.is( textile.convert( tx ), + "

        A footnote reference1.

        \n\ +

        1 The footnote.

        ", tx ); +}); + + +test( 'block code', function ( t ) { + let tx = "bc. "; + t.is( textile.convert( tx ), + "
        <script>\n\
        +// a Javascript example\n\
        +alert(\"Hello World\");\n\
        +</script>
        ", tx ); +}); + + +test( 'preformatted text', function ( t ) { + let tx = "pre. Pre-formatted\n\ +text"; + t.is( textile.convert( tx ), + "
        Pre-formatted\n\
        +text
        ", tx ); +}); + + +test( 'notextile', function ( t ) { + let tx = "notextile. \n\ +"; + t.is( textile.convert( tx ), + "\n\ +", tx ); +}); + + +test( 'class attribute', function ( t ) { + let tx = "p(myclass). My classy paragraph."; + t.is( textile.convert( tx ), + "

        My classy paragraph.

        ", tx ); +}); + + +test( 'id attribute', function ( t ) { + let tx = "p(#myid). My ID paragraph."; + t.is( textile.convert( tx ), + "

        My ID paragraph.

        ", tx ); +}); + + +test( 'style attribute', function ( t ) { + let tx = "p{color:red}. Red rum."; + t.is( textile.convert( tx ), + "

        Red rum.

        ", tx ); +}); + + +test( 'lang attribute', function ( t ) { + let tx = "p[fr-fr]. En français."; + t.is( textile.convert( tx ), + "

        En français.

        ", tx ); +}); + + +test( 'phrase modifiers', function ( t ) { + let tx = "A *(myclass)classy* phrase."; + t.is( textile.convert( tx ), + "

        A classy phrase.

        ", tx ); +}); + + +test( 'phrase modifiers 2', function ( t ) { + let tx = "An _(#myid2)ID_ phrase."; + t.is( textile.convert( tx ), + "

        An ID phrase.

        ", tx ); +}); + + +test( 'phrase modifiers 3', function ( t ) { + let tx = "The %{color:blue}blue% room."; + t.is( textile.convert( tx ), + "

        The blue room.

        ", tx ); +}); + + +test( 'block and phrase attributes combined', function ( t ) { + let tx = "p(myclass#myid3){color:green}[de-de]. A complex paragraph."; + t.is( textile.convert( tx ), + "

        A complex paragraph.

        ", tx ); +}); + + +test( 'block and phrase attributes combined 2', function ( t ) { + let tx = "A ??(myclass#myid4){color:green}[de-de]complex?? phrase."; + t.is( textile.convert( tx ), + "

        A complex phrase.

        ", tx ); +}); + + +test( 'extended blocks', function ( t ) { + let tx = "bq.. A quote.\n\n\ +The quote continued.\n\n\ +p. Back to paragraph text."; + t.is( textile.convert( tx ), + "
        \n\ +

        A quote.

        \n\ +

        The quote continued.

        \n\ +
        \n\ +

        Back to paragraph text.

        ", tx ); +}); + + +test( 'extended block code', function ( t ) { + let tx = "A PHP code example.\n\n\ +bc.. \n\n\ +p. Following paragraph."; + t.is( textile.convert( tx ), + "

        A PHP code example.

        \n\ +
        <?php\n\
        +function hello() {\n\
        +// display a hello message\n\n\
        +print \"Hello, World\";\n\
        +}\n\
        +?>
        \n\ +

        Following paragraph.

        ", tx ); +}); + + +test( 'extended block attributes', function ( t ) { + let tx = "p(myclass).. A classy paragraph.\n\n\ +Another classy paragraph.\n\n\ +p. Not so classy."; + t.is( textile.convert( tx ), + "

        A classy paragraph.

        \n\ +

        Another classy paragraph.

        \n\ +

        Not so classy.

        ", tx ); +}); + + +test( 'extended block quote attributes', function ( t ) { + let tx = "bq(myclass).. Quote paragraph 1.\n\n\ +Paragraph 2."; + t.is( textile.convert( tx ), + "
        \n\ +

        Quote paragraph 1.

        \n\ +

        Paragraph 2.

        \n\ +
        ", tx ); +}); + + +test( 'extended block code attributes', function ( t ) { + let tx = "bc(myclass).. Code block 1.\n\n\ +Code block 2."; + t.is( textile.convert( tx ), + "
        Code block 1.\n\n\
        +Code block 2.
        ", tx ); +}); + + +test( 'raw xhtml left in tact', function ( t ) { + let tx = "bold and italic, the hard way."; + t.is( textile.convert( tx ), + "

        bold and italic, the hard way.

        ", tx ); +}); + + +test( 'paragraphs entirely raw xhtml', function ( t ) { + let tx = "
        My div
        "; + t.is( textile.convert( tx ), + "
        My div
        ", tx ); +}); + + +test( 'paragraphs with inline xhtml', function ( t ) { + let tx = "\"image\""; + t.is( textile.convert( tx ), + "

        \"image\"

        ", tx ); +}); + + +test( 'paragraphs with inline xhtml 2', function ( t ) { + let tx = "I'll make my own way."; + t.is( textile.convert( tx ), + "

        I’ll make my own way.

        ", tx ); +}); + + +test( 'paragraphs partly enclosed in xhtml block tags', function ( t ) { + let tx = "
        inside
        and outside."; + t.is( textile.convert( tx ), + "
        inside
        \n\ +

        and outside.

        ", tx ); +}); + + +test( 'complex xhtml blocks', function ( t ) { + let tx = "
        \n\ + My div\n\ +
        "; + t.is( textile.convert( tx ), + "
        \n\ +My div\n\ +
        ", tx ); +}); + + +test( 'complex xhtml blocks 2', function ( t ) { + let tx = "notextile..
        \n\n\ +My div\n\n\ +
        "; + t.is( textile.convert( tx ), + "
        \n\n\ +My div\n\n\ +
        ", tx ); +}); + + +test( 'complex xhtml blocks with inline formatting', function ( t ) { + let tx = "
        \n\ + My *div*\n\ +
        "; + t.is( textile.convert( tx ), + "
        \n\ +My div\n\ +
        ", tx ); +}); + + +test( 'explicit pre escapement', function ( t ) { + let tx = "
        \n\
        +A HTML example\n\
        +
        "; + t.is( textile.convert( tx ), + "
        \n\
        +A HTML <b>example</b>\n\
        +
        ", tx ); +}); + + +test( 'explicit code escapement', function ( t ) { + let tx = "\n\ +Another HTML example\n\ +"; + t.is( textile.convert( tx ), + "

        \n\ +Another HTML <b>example</b>\n\ +

        ", tx ); +}); + + +test( 'notextile tags', function ( t ) { + let tx = "\n\ +p. Leave me alone\n\ +"; + t.is( textile.convert( tx ), + "p. Leave me alone", tx ); +}); + + +test( 'left aligned text', function ( t ) { + let tx = "p<. Left-aligned paragraph."; + t.is( textile.convert( tx ), + "

        Left-aligned paragraph.

        ", tx ); +}); + + +test( 'right aligned text', function ( t ) { + let tx = "h3>. Right-aligned heading."; + t.is( textile.convert( tx ), + "

        Right-aligned heading.

        ", tx ); +}); + + +test( 'justified text', function ( t ) { + let tx = "p<>. Justified paragraph."; + t.is( textile.convert( tx ), + "

        Justified paragraph.

        ", tx ); +}); + + +test( 'centered text', function ( t ) { + let tx = "h3=. Centered heading."; + t.is( textile.convert( tx ), + "

        Centered heading.

        ", tx ); +}); + + +test( 'padding', function ( t ) { + let tx = "p(. Left pad 1em."; + t.is( textile.convert( tx ), + "

        Left pad 1em.

        ", tx ); +}); + + +test( 'padding 2', function ( t ) { + let tx = "p)). Right pad 2em."; + t.is( textile.convert( tx ), + "

        Right pad 2em.

        ", tx ); +}); + + +test( 'padding 3', function ( t ) { + let tx = "p(). Left and right pad 1em."; + t.is( textile.convert( tx ), + "

        Left and right pad 1em.

        ", tx ); +}); + + +test( 'numeric lists', function ( t ) { + let tx = "# Item one\n\ +# Item two\n\ +# Item three"; + t.is( textile.convert( tx ), + "
          \n\ +\t
        1. Item one
        2. \n\ +\t
        3. Item two
        4. \n\ +\t
        5. Item three
        6. \n\ +
        ", tx ); +}); + + +test( 'bulleted lists', function ( t ) { + let tx = "* Item A\n\ +* Item B\n\ +* Item C"; + t.is( textile.convert( tx ), + "", tx ); +}); + + +test( 'nested lists', function ( t ) { + let tx = "# Item one\n\ +## Item one-A\n\ +## Item one-B\n\ +### Item one-B-a\n\ +# Item two"; + t.is( textile.convert( tx ), + "
          \n\ +\t
        1. Item one\n\ +\t
            \n\ +\t\t
          1. Item one-A
          2. \n\ +\t\t
          3. Item one-B\n\ +\t\t
              \n\ +\t\t\t
            1. Item one-B-a
            2. \n\ +\t\t
          4. \n\ +\t
        2. \n\ +\t
        3. Item two
        4. \n\ +
        ", tx ); +}); + + +test( 'tables', function ( t ) { + let tx = "|a|simple|table|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        asimpletable
        ", tx ); +}); + + +test( 'table heading cells', function ( t ) { + let tx = "|_. a|_. table|_. heading|\n\ +|a|table|row|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        atableheading
        atablerow
        ", tx ); +}); + + +test( 'cell attributes', function ( t ) { + let tx = "|a|{color:red}. styled|cell|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        astyledcell
        ", tx ); +}); + + +test( 'row attributes', function ( t ) { + let tx = "(rowclass). |a|classy|row|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        aclassyrow
        ", tx ); +}); + + +test( 'table attributes', function ( t ) { + let tx = "table(tableclass).\n\ +|a|classy|table|\n\ +|a|classy|table|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        aclassytable
        aclassytable
        ", tx ); +}); + + +test( 'vertical alignment', function ( t ) { + let tx = "|^. top alignment|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\n\ +
        top alignment
        ", tx ); +}); + + +test( 'vertical alignment 2', function ( t ) { + let tx = "|-. middle alignment|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\n\ +
        middle alignment
        ", tx ); +}); + + +test( 'vertical alignment 3', function ( t ) { + let tx = "|~. bottom alignment|"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\n\ +
        bottom alignment
        ", tx ); +}); + + +test( 'column span', function ( t ) { + let tx = "|\\2. spans two cols |\n\ +| col 1 | col 2 |"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +
        spans two cols
        col 1 col 2
        ", tx ); +}); + + +test( 'row span', function ( t ) { + let tx = "|/3. spans 3 rows | row a |\n\ +| row b |\n\ +| row c |"; + t.is( textile.convert( tx ), + "\n\ +\t\n\ +\t\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +\t\n\ +\t\t\n\ +\t\n\ +
        spans 3 rows row a
        row b
        row c
        ", tx ); +}); + + +test( 'whitespace required', function ( t ) { + let tx = "this*won't*work"; + t.is( textile.convert( tx ), + "

        this*won’t*work

        ", tx ); +}); + + +test( 'modifier without whitespace', function ( t ) { + let tx = "this[*will*]work"; + t.is( textile.convert( tx ), + "

        thiswillwork

        ", tx ); +}); + + +test( 'modifier without whitespace 2', function ( t ) { + let tx = "1[^st^], 2[^nd^], 3[^rd^]."; + t.is( textile.convert( tx ), + "

        1st, 2nd, 3rd.

        ", tx ); +}); + + +test( 'modifier without whitespace 3', function ( t ) { + let tx = "2 log[~n~]"; + t.is( textile.convert( tx ), + "

        2 logn

        ", tx ); +}); + + +test( 'modifier without whitespace 4', function ( t ) { + let tx = "A close[!/img.gif!]image.\n\ +A tight[\"text\":http://thresholdstate.com/]link.\n\ +A [\"footnoted link\":http://thresholdstate.com/][1]."; + t.is( textile.convert( tx ), + "

        A close\"\"image.
        \n\ +A tighttextlink.
        \n\ +A footnoted link1.

        ", tx ); +}); + diff --git a/textile.min.js b/textile.min.js deleted file mode 100644 index 81b8010..0000000 --- a/textile.min.js +++ /dev/null @@ -1 +0,0 @@ -(function(){"use strict";var re={_cache:{},pattern:{punct:"[!-/:-@\\[\\\\\\]-`{-~]",space:"\\s"},escape:function(src){return src.replace(/[\-\[\]\{\}\(\)\*\+\?\.\,\\\^\$\|\#\s]/g,"\\$&")},collapse:function(src){return src.replace(/(?:#.*?(?:\n|$))/g,"").replace(/\s+/g,"")},expand_patterns:function(src){return src.replace(/\[\:\s*(\w+)\s*\:\]/g,function(m,k){return k in re.pattern?re.expand_patterns(re.pattern[k]):k})},isRegExp:function(r){return Object.prototype.toString.call(r)==="[object RegExp]"},compile:function(src,flags){if(re.isRegExp(src)){if(arguments.length===1){flags=(src.global?"g":"")+(src.ignoreCase?"i":"")+(src.multiline?"m":"")}src=src.source}var ckey=src+(flags||"");if(ckey in re._cache){return re._cache[ckey]}var rx=re.expand_patterns(src);if(flags&&/x/.test(flags)){rx=re.collapse(rx)}if(flags&&/s/.test(flags)){rx=rx.replace(/([^\\])\./g,"$1[^\\0]")}flags=(flags||"").replace(/[^gim]/g,"");return re._cache[ckey]=new RegExp(rx,flags)}};var JSONML={escape:function(text,esc_quotes){return text.replace(/&(?!(#\d{2,}|#x[\da-fA-F]{2,}|[a-zA-Z][a-zA-Z1-4]{1,6});)/g,"&").replace(//g,">").replace(/"/g,esc_quotes?""":'"').replace(/'/g,esc_quotes?"'":"'")},toHTML:function(jsonml){jsonml=jsonml.concat();if(typeof jsonml==="string"){return JSONML.escape(jsonml)}var tag=jsonml.shift(),attributes={},content=[],tag_attrs="",a;if(jsonml.length&&typeof jsonml[0]==="object"&&!_isArray(jsonml[0])){attributes=jsonml.shift()}while(jsonml.length){content.push(JSONML.toHTML(jsonml.shift()))}for(a in attributes){tag_attrs+=attributes[a]==null?" "+a:" "+a+'="'+JSONML.escape(String(attributes[a]),true)+'"'}if(tag=="!"){return""}else if(tag in html_singletons){return"<"+tag+tag_attrs+" />"}else{return"<"+tag+tag_attrs+">"+content.join("")+""}}};function merge(a,b){if(b){for(var k in b){a[k]=b[k]}}return a}var _isArray=Array.isArray||function(a){return Object.prototype.toString.call(a)==="[object Array]"};re.pattern["blocks"]="(?:b[qc]|div|notextile|pre|h[1-6]|fn\\d+|p|###)";re.pattern["pba_class"]="\\([^\\)]+\\)";re.pattern["pba_style"]="\\{[^\\}]+\\}";re.pattern["pba_lang"]="\\[[^\\[\\]]+\\]";re.pattern["pba_align"]="(?:<>|<|>|=)";re.pattern["pba_pad"]="[\\(\\)]+";re.pattern["pba_attr"]="(?:[:pba_class:]|[:pba_style:]|[:pba_lang:]|[:pba_align:]|[:pba_pad:])*";re.pattern["url_punct"]="[.,«»″‹›!?]";re.pattern["html_id"]="[a-zA-Z][a-zA-Z\\d:]*";re.pattern["html_attr"]="(?:\"[^\"]+\"|'[^']+'|[^>\\s]+)";re.pattern["tx_urlch"]='[\\w"$\\-_.+!*\'(),";\\/?:@=&%#{}|\\\\^~\\[\\]`]';re.pattern["tx_cite"]=":((?:[^\\s()]|\\([^\\s()]+\\)|[()])+?)(?=[!-\\.:-@\\[\\\\\\]-`{-~]+(?:$|\\s)|$|\\s)";re.pattern["listhd"]="[\\t ]*[\\#\\*]*(\\*|\\#(?:_|\\d+)?)[:pba_attr:](?: \\S|\\.\\s*(?=\\S|\\n))";re.pattern["ucaps"]="A-Z"+"À-ÖØ-Þ"+"ĀĂĄĆĈĊČĎĐĒĔĖĘĚĜĞĠĢĤĦĨĪĬĮİIJĴĶĹĻĽĿ"+"ŁŃŅŇŊŌŎŐŒŔŖŘŚŜŞŠŢŤŦŨŪŬŮŰŲŴŶŸŹŻŽ"+"ƁƂƄƆƇƉ-ƋƎ-ƑƓƔƖ-ƘƜƝƟƠƢƤƦƧƩƬƮƯƱ-ƳƵƷƸƼ"+"DŽLJNJǍǏǑǓǕǗǙǛǞǠǢǤǦǨǪǬǮDZǴǶ-ǸǺǼǾ"+"ȀȂȄȆȈȊȌȎȐȒȔȖȘȚȜȞȠȢȤȦȨȪȬȮȰȲȺȻȽȾ"+"ɁɃ-ɆɈɊɌɎ"+"ḀḂḄḆḈḊḌḎḐḒḔḖḘḚḜḞḠḢḤḦḨḪḬḮḰḲḴḶḸḺḼḾṀ"+"ṂṄṆṈṊṌṎṐṒṔṖṘṚṜṞṠṢṤṦṨṪṬṮṰṲṴṶṸṺṼṾ"+"ẀẂẄẆẈẊẌẎẐẒẔẞẠẢẤẦẨẪẬẮẰẲẴẶẸẺẼẾ"+"ỀỂỄỆỈỊỌỎỐỒỔỖỘỚỜỞỠỢỤỦỨỪỬỮỰỲỴỶỸỺỼỾ"+"ⱠⱢ-ⱤⱧⱩⱫⱭ-ⱰⱲⱵⱾⱿ"+"ꜢꜤꜦꜨꜪꜬꜮꜲꜴꜶꜸꜺꜼꜾ"+"ꝀꝂꝄꝆꝈꝊꝌꝎꝐꝒꝔꝖꝘꝚꝜꝞꝠꝢꝤꝦꝨꝪꝬꝮꝹꝻꝽꝾ"+"ꞀꞂꞄꞆꞋꞍꞐꞒꞠꞢꞤꞦꞨꞪ";var re_block=re.compile(/^([:blocks:])/),re_block_se=re.compile(/^[:blocks:]$/),re_block_normal=re.compile(/^(.*?)($|\r?\n(?=[:listhd:])|\r?\n(?:\s*\n|$)+)/,"s"),re_block_extended=re.compile(/^(.*?)($|\r?\n(?=[:listhd:])|\r?\n+(?=[:blocks:][:pba_attr:]\.))/,"s"),re_ruler=/^(\-\-\-+|\*\*\*+|___+)(\r?\n\s+|$)/,re_list=re.compile(/^((?:[:listhd:][^\0]*?(?:\r?\n|$))+)(\s*\n|$)/,"s"),re_list_item=re.compile(/^([\#\*]+)([^\0]+?)(\n(?=[:listhd:])|$)/,"s"),re_deflist=/^((?:- (?:[^\n]\n?)+?)+:=(?: *\n[^\0]+?=:(?:\n|$)|(?:[^\0]+?(?:$|\n(?=\n|- )))))+/,re_deflist_item=/^((?:- (?:[^\n]\n?)+?)+):=( *\n[^\0]+?=:\s*(?:\n|$)|(?:[^\0]+?(?:$|\n(?=\n|- ))))/,re_table=re.compile(/^((?:table[:pba_attr:]\.(?:\s(.+?))\s*\n)?(?:(?:[:pba_attr:]\.[^\n\S]*)?\|.*?\|[^\n\S]*(?:\n|$))+)([^\n\S]*\n)?/,"s"),re_table_head=/^table(_?)([^\n]*?)\.(?:[ \t](.+?))?\s*\n/,re_table_row=re.compile(/^(?:\|([~\^\-][:pba_attr:])\.\s*\n)?([:pba_attr:]\.[^\n\S]*)?\|(.*?)\|[^\n\S]*(\n|$)/,"s"),re_table_caption=/^\|=([^\n+]*)\n/,re_table_colgroup=/^\|:([^\n+]*)\|[\r\t ]*\n/,re_table_rowgroup=/^\|([\^\-\~])([^\n+]*)\.[ \t\r]*\n/,re_fenced_phrase=/^\[(__?|\*\*?|\?\?|[\-\+\^~@%])([^\n]+)\1\]/,re_phrase=/^([\[\{]?)(__?|\*\*?|\?\?|[\-\+\^~@%])/,re_text=re.compile(/^.+?(?=[\\(\n*)/),re_html_tag=re.compile(/^<([:html_id:])((?:\s[^=\s\/]+(?:\s*=\s*[:html_attr:])?)+)?\s*(\/?)>(\n*)/),re_html_comment=re.compile(/^/,"s"),re_html_end_tag=re.compile(/^<\/([:html_id:])([^>]*)>/),re_html_attr=re.compile(/^\s*([^=\s]+)(?:\s*=\s*("[^"]+"|'[^']+'|[^>\s]+))?/),re_entity=/&(#\d\d{2,}|#x[\da-fA-F]{2,}|[a-zA-Z][a-zA-Z1-4]{1,6});/,re_dimsign=/([\d\.,]+['"]? ?)x( ?)(?=[\d\.,]['"]?)/g,re_emdash=/(^|[\s\w])--([\s\w]|$)/g,re_trademark=/(\b ?|\s|^)(?:\((?:TM|tm)\)|\[(?:TM|tm)\])/g,re_registered=/(\b ?|\s|^)(?:\(R\)|\[R\])/gi,re_copyright=/(\b ?|\s|^)(?:\(C\)|\[C\])/gi,re_apostrophe=/(\w)\'(\w)/g,re_double_prime=re.compile(/(\d*[\.,]?\d+)"(?=\s|$|[:punct:])/g),re_single_prime=re.compile(/(\d*[\.,]?\d+)'(?=\s|$|[:punct:])/g),re_closing_dquote=re.compile(/([^\s\[\(])"(?=$|\s|[:punct:])/g),re_closing_squote=re.compile(/([^\s\[\(])'(?=$|\s|[:punct:])/g),re_pba_classid=/^\(([^\(\)\n]+)\)/,re_pba_padding_l=/^(\(+)/,re_pba_padding_r=/^(\)+)/,re_pba_align_blk=/^(<>|<|>|=)/,re_pba_align_img=/^(<|>|=)/,re_pba_valign=/^(~|\^|\-)/,re_pba_colspan=/^\\(\d+)/,re_pba_rowspan=/^\/(\d+)/,re_pba_styles=/^\{([^\}]*)\}/,re_pba_css=/^\s*([^:\s]+)\s*:\s*(.+)\s*$/,re_pba_lang=/^\[([^\[\]\n]+)\]/;var phrase_convert={"*":"strong","**":"b","??":"cite",_:"em",__:"i","-":"del","%":"span","+":"ins","~":"sub","^":"sup","@":"code"};var html_singletons={br:1,hr:1,img:1,link:1,meta:1,wbr:1,area:1,param:1,input:1,option:1,base:1,col:1};var pba_align_lookup={"<":"left","=":"center",">":"right","<>":"justify"};var pba_valign_lookup={"~":"bottom","^":"top","-":"middle"};var allowed_blocktags={p:0,hr:0,ul:1,ol:0,li:0,div:1,pre:0,object:1,script:0,noscript:0,blockquote:1,notextile:1};function ribbon(feed){var _slot=null,org=feed+"",pos=0;return{save:function(){_slot=pos},load:function(){pos=_slot;feed=org.slice(pos)},advance:function(n){pos+=typeof n==="string"?n.length:n;return feed=org.slice(pos)},lookbehind:function(nchars){nchars=nchars==null?1:nchars;return org.slice(pos-nchars,pos)},startsWith:function(s){return feed.substring(0,s.length)===s},valueOf:function(){return feed},toString:function(){return feed}}}function builder(arr){var _arr=_isArray(arr)?arr:[];return{add:function(node){if(typeof node==="string"&&typeof _arr[_arr.length-1]==="string"){_arr[_arr.length-1]+=node}else if(_isArray(node)){var f=node.filter(function(s){return s!==undefined});_arr.push(f)}else if(node){_arr.push(node)}return this},merge:function(s){for(var i=0,l=s.length;i=0;i--){var head=_stack[i];if(head[0]===tag){_stack.splice(i);list=_stack[_stack.length-1]||root;break}}}src.advance(m[0])}else if((m=re_html_tag.exec(src))&&oktag(m[1])){src.advance(m[0]);tag=m[1];var single=m[3]||m[1]in html_singletons,tail=m[4],element=[tag];if(m[2]){element.push(parse_html_attr(m[2]))}if(single){list.push(element);if(tail){list.push(tail)}}else{if(tail){element.push(tail)}_stack.push(element);list.push(element);list=element}}else{m=/([^<]+|[^\0])/.exec(src);if(m){list.push(m[0])}src.advance(m?m[0].length||1:1)}}while(src.valueOf());return root}function parse_attr(input,element,end_token){input+="";if(!input||element==="notextile"){return undefined}var m,st={},o={style:st},remaining=input,is_block=/^(?:table|t[dh]|t(?:foot|head|body))$/.test(element)||re_block_se.test(element),is_img=element==="img",is_list=element==="li",is_phrase=!is_block&&!is_img&&element!=="a",re_pba_align=is_img?re_pba_align_img:re_pba_align_blk;do{if(m=re_pba_styles.exec(remaining)){m[1].split(";").forEach(function(p){var d=p.match(re_pba_css);if(d){st[d[1]]=d[2]}});remaining=remaining.slice(m[0].length);continue}if(m=re_pba_lang.exec(remaining)){var rm=remaining.slice(m[0].length);if(!rm&&is_phrase||end_token&&end_token===rm.slice(0,end_token.length)){m=null}else{o["lang"]=m[1];remaining=remaining.slice(m[0].length)}continue}if(m=re_pba_classid.exec(remaining)){var rm=remaining.slice(m[0].length);if(!rm&&is_phrase||end_token&&(rm[0]===" "||end_token===rm.slice(0,end_token.length))){m=null}else{var bits=m[1].split("#");if(bits[0]){o["class"]=bits[0]}if(bits[1]){o["id"]=bits[1]}remaining=rm}continue}if(is_block||is_list){if(m=re_pba_padding_l.exec(remaining)){st["padding-left"]=m[1].length+"em";remaining=remaining.slice(m[0].length);continue}if(m=re_pba_padding_r.exec(remaining)){st["padding-right"]=m[1].length+"em";remaining=remaining.slice(m[0].length);continue}}if(is_img||is_block||is_list){if(m=re_pba_align.exec(remaining)){var align=pba_align_lookup[m[1]];if(is_img){o["align"]=align}else{st["text-align"]=align}remaining=remaining.slice(m[0].length);continue}}if(element==="td"||element==="tr"){if(m=re_pba_valign.exec(remaining)){st["vertical-align"]=pba_valign_lookup[m[1]];remaining=remaining.slice(m[0].length);continue}}if(element==="td"){if(m=re_pba_colspan.exec(remaining)){o["colspan"]=m[1];remaining=remaining.slice(m[0].length);continue}if(m=re_pba_rowspan.exec(remaining)){o["rowspan"]=m[1];remaining=remaining.slice(m[0].length);continue}}}while(m);var s=[];for(var v in st){s.push(v+":"+st[v])}if(s.length){o.style=s.join(";")}else{delete o.style}return remaining==input?undefined:[input.length-remaining.length,o]}function parse_glyphs(src){if(typeof src!=="string"){return src}return src.replace(/([^\-]|^)->/,"$1→").replace(re_dimsign,"$1×$2").replace(/([^.]?)\.{3}/g,"$1…").replace(re_emdash,"$1—$2").replace(/ - /g," – ").replace(re_trademark,"$1™").replace(re_registered,"$1®").replace(re_copyright,"$1©").replace(re_double_prime,"$1″").replace(re_closing_dquote,"$1”").replace(/"/g,"“").replace(re_single_prime,"$1′").replace(re_apostrophe,"$1’$2").replace(re_closing_squote,"$1’").replace(/'/g,"‘").replace(/[\(\[]1\/4[\]\)]/,"¼").replace(/[\(\[]1\/2[\]\)]/,"½").replace(/[\(\[]3\/4[\]\)]/,"¾").replace(/[\(\[]o[\]\)]/,"°").replace(/[\(\[]\+\/\-[\]\)]/,"±")}function list_pad(n){var s="\n";while(n--){s+=" "}return s}function parse_list(src,options){src=ribbon(src.replace(/(^|\r?\n)[\t ]+/,"$1"));var stack=[],curr_idx={},last_idx=options._lst||{},list_pba,item_index=0,m,n,s;while(m=re_list_item.exec(src)){var item=["li"],start_index=0,dest_level=m[1].length,type=m[1].substr(-1)==="#"?"ol":"ul",new_li=null,lst,par,pba,r;if(n=/^(_|\d+)/.exec(m[2])){item_index=isFinite(n[1])?parseInt(n[1],10):last_idx[dest_level]||curr_idx[dest_level]||1;m[2]=m[2].slice(n[1].length)}if(pba=parse_attr(m[2],"li")){m[2]=m[2].slice(pba[0]);pba=pba[1]}if(/^\.\s*$/.test(m[2])){list_pba=pba||{};src.advance(m[0]);continue}while(stack.lengthdest_level){r=stack.pop();r.ul.push(list_pad(stack.length));if(r.att===1&&!r.ul[3][1].substr){merge(r.ul[1],r.ul[3].splice(1,1)[0])}}par=stack[stack.length-1];if(item_index){par.ul[1].start=curr_idx[dest_level]=item_index;item_index=0}if(list_pba){par.att=9;merge(par.ul[1],list_pba);list_pba=null}if(!new_li){par.ul.push(list_pad(stack.length),item);par.li=item}if(pba){par.li.push(pba);par.att++}Array.prototype.push.apply(par.li,parse_inline(m[2].trim(),options));src.advance(m[0]);curr_idx[dest_level]=(curr_idx[dest_level]||0)+1}options._lst=curr_idx;while(stack.length){s=stack.pop();s.ul.push(list_pad(stack.length));if(s.att===1&&!s.ul[3][1].substr){merge(s.ul[1],s.ul[3].splice(1,1)[0])}}return s.ul}function parse_deflist(src,options){src=ribbon(src.trim());var deflist=["dl","\n"],terms,def,m;while(m=re_deflist_item.exec(src)){terms=m[1].split(/(?:^|\n)\- /).slice(1);while(terms.length){deflist.push(" ",["dt"].concat(parse_inline(terms.shift().trim(),options)),"\n")}def=m[2].trim();deflist.push(" ",["dd"].concat(/=:$/.test(def)?parse_blocks(def.slice(0,-2).trim(),options):parse_inline(def,options)),"\n");src.advance(m[0])}return deflist}function parse_colgroup(src){var colgroup=["colgroup",{}];src.split("|").forEach(function(s,is_col){var d=s.trim(),col=is_col?{}:colgroup[1],m;if(d){if(m=/^\\(\d+)/.exec(d)){col.span=+m[1];d=d.slice(m[0].length)}if(m=parse_attr(d,"col")){merge(col,m[1]);d=d.slice(m[0])}if(m=/\b\d+\b/.exec(d)){col.width=+m[0]}}if(is_col){colgroup.push("\n ",["col",col])}});return colgroup.concat(["\n "])}function parse_table(src,options){src=ribbon(src.trim());var rowgroups=[],colgroup,caption,t_attr={},t_curr,row,inner,pba,more,m,extended=0;var set_rowgroup=function(type,pba){t_curr=[type,pba||{}];rowgroups.push(t_curr)};if(m=re_table_head.exec(src)){src.advance(m[0]);pba=parse_attr(m[2],"table");if(pba){merge(t_attr,pba[1])}if(m[3]){t_attr.summary=m[3]}}if(m=re_table_caption.exec(src)){caption=["caption"];if(pba=parse_attr(m[1],"caption")){caption.push(pba[1]);m[1]=m[1].slice(pba[0])}if(/\./.test(m[1])){caption.push(m[1].slice(1).replace(/\|\s*$/,"").trim());extended++;src.advance(m[0])}else{caption=null}}do{if(m=re_table_colgroup.exec(src)){colgroup=parse_colgroup(m[1]);extended++}else if(m=re_table_rowgroup.exec(src)){var tag=m[1]==="^"?"thead":m[1]==="~"?"tfoot":m[1]==="-"?"tbody":"tbody";pba=parse_attr(m[2]+" ",tag);set_rowgroup(tag,pba&&pba[1]);extended++}else if(m=re_table_row.exec(src)){if(!t_curr){set_rowgroup("tbody")}row=["tr"];if(m[2]&&(pba=parse_attr(m[2],"tr"))){row.push(pba[1])}t_curr.push("\n ",row);inner=ribbon(m[3]);do{inner.save();var th=inner.startsWith("_"),cell=[th?"th":"td"];if(th){inner.advance(1)}pba=parse_attr(inner,"td");if(pba){inner.advance(pba[0]);cell.push(pba[1])}if(pba||th){var p=/^\.\s*/.exec(inner);if(p){inner.advance(p[0])}else{cell=["td"];inner.load()}}var mx=/^(==.*?==|[^\|])*/.exec(inner);cell=cell.concat(parse_inline(mx[0],options));row.push("\n ",cell);more=inner.valueOf().charAt(mx[0].length)==="|";inner.advance(mx[0].length+1)}while(more);row.push("\n ")}if(m){src.advance(m[0])}}while(m);var table=["table",t_attr];if(extended){if(caption){table.push("\n ",caption)}if(colgroup){table.push("\n ",colgroup)}rowgroups.forEach(function(tbody){table.push("\n ",tbody.concat(["\n "]))})}else{table=table.concat(reindent(rowgroups[0].slice(2),-1))}table.push("\n");return table}function parse_inline(src,options){src=ribbon(src);var list=builder(),m,pba;do{src.save();if(src.startsWith("\r\n")){src.advance(1)}if(src.startsWith("\n")){src.advance(1);if(options.breaks){list.add(["br"])}list.add("\n");continue}if(m=/^==(.*?)==/.exec(src)){src.advance(m[0]);list.add(m[1]);continue}var behind=src.lookbehind(1);var boundary=!behind||/^[\s>.,"'?!;:()]$/.test(behind);if((m=re_phrase.exec(src))&&(boundary||m[1])){src.advance(m[0]);var tok=m[2],fence=m[1],phrase_type=phrase_convert[tok],code=phrase_type==="code";if(pba=!code&&parse_attr(src,phrase_type,tok)){src.advance(pba[0]);pba=pba[1]}var m_mid;var m_end;if(fence==="["){m_mid="^(.*?)";m_end="(?:])"}else if(fence==="{"){m_mid="^(.*?)";m_end="(?:})"}else{var t1=re.escape(tok.charAt(0));m_mid=code?"^(\\S+|\\S+.*?\\S)":"^([^\\s"+t1+"]+|[^\\s"+t1+"].*?\\S("+t1+"*))";m_end="(?=$|[\\s.,\"'!?;:()«»„“”‚‘’])"}var rx=re.compile(m_mid+"("+re.escape(tok)+")"+m_end);if((m=rx.exec(src))&&m[1]){src.advance(m[0]);if(code){list.add([phrase_type,m[1]])}else{list.add([phrase_type,pba].concat(parse_inline(m[1],options)))}continue}src.load()}if((m=re_image.exec(src))||(m=re_image_fenced.exec(src))){src.advance(m[0]);pba=m[1]&&parse_attr(m[1],"img");var attr=pba?pba[1]:{src:""},img=["img",attr];attr.src=m[2];attr.alt=m[3]?attr.title=m[3]:"";if(m[4]){img=["a",{href:m[4]},img]}list.add(img);continue}if(m=re_html_comment.exec(src)){src.advance(m[0]);list.add(["!",m[1]]);continue}if(m=re_html_tag.exec(src)){src.advance(m[0]);var tag=m[1],single=m[3]||m[1]in html_singletons,element=[tag],tail=m[4];if(m[2]){element.push(parse_html_attr(m[2]))}if(single){list.add(element).add(tail);continue}else{var re_end_tag=re.compile("^(.*?)()","s");if(m=re_end_tag.exec(src)){src.advance(m[0]);if(tag==="code"){element.push(tail,m[1])}else if(tag==="notextile"){list.merge(parse_inline(m[1],options));continue}else{element=element.concat(parse_inline(m[1],options))}list.add(element);continue}}src.load()}if((m=re_footnote.exec(src))&&/\S/.test(behind)){src.advance(m[0]);list.add(["sup",{"class":"footnote",id:"fnr"+m[1]},m[2]==="!"?m[1]:["a",{href:"#fn"+m[1]},m[1]]]);continue}if(m=re_caps.exec(src)){src.advance(m[0]);var caps=["span",{"class":"caps"},m[1]];if(m[2]){caps=["acronym",{title:m[2]},caps]}list.add(caps);continue}if(boundary&&(m=re_link.exec(src))||(m=re_link_fenced.exec(src))){src.advance(m[0]);var title=m[1].match(re_link_title),inner=title?m[1].slice(0,m[1].length-title[0].length):m[1];if(pba=parse_attr(inner,"a")){inner=inner.slice(pba[0]);pba=pba[1]}else{pba={}}if(title&&!inner){inner=title[0];title=""}pba.href=m[2];if(title){pba.title=title[1]}list.add(["a",pba].concat(parse_inline(inner.replace(/^(\.?\s*)/,""),options)));continue}m=/([a-zA-Z0-9,.':]+|[ \f\r\t\v\xA0\u2028\u2029]+|[^\0])/.exec(src);if(m){list.add(m[0])}src.advance(m?m[0].length||1:1)}while(src.valueOf());return list.get().map(parse_glyphs)}function parse_blocks(src,options){var list=builder(),paragraph=function(s,tag,pba,linebreak){tag=tag||"p";var out=[];s.split(/(?:\r?\n){2,}/).forEach(function(bit,i){if(tag==="p"&&/^\s/.test(bit)){bit=bit.replace(/\r?\n[\t ]/g," ").trim();out=out.concat(parse_inline(bit,options))}else{if(linebreak&&i){out.push(linebreak)}out.push(pba?[tag,pba].concat(parse_inline(bit,options)):[tag].concat(parse_inline(bit,options)))}});return out},link_refs={},m;src=ribbon(src.replace(/^( *\r?\n)+/,""));while(src.valueOf()){src.save();if(m=re_link_ref.exec(src)){src.advance(m[0]);link_refs[m[1]]=m[2];continue}list.linebreak();if(m=re_block.exec(src)){src.advance(m[0]);var block_type=m[0],pba=parse_attr(src,block_type);if(pba){src.advance(pba[0]);pba=pba[1]}if(m=/^\.(\.?)(?:\s|(?=:))/.exec(src)){var extended=!!m[1];m=(extended?re_block_extended:re_block_normal).exec(src.advance(m[0]));src.advance(m[0]);if(block_type==="bq"){var cite,inner=m[1];if(m=/^:(\S+)\s+/.exec(inner)){if(!pba){pba={}}pba.cite=m[1];inner=inner.slice(m[0].length)}list.add(["blockquote",pba,"\n"].concat(paragraph(inner,"p",copy_pba(pba,{cite:1,id:1}),"\n")).concat(["\n"]))}else if(block_type==="bc"){var sub_pba=pba?copy_pba(pba,{id:1}):null;list.add(["pre",pba,sub_pba?["code",sub_pba,m[1]]:["code",m[1]]])}else if(block_type==="notextile"){list.merge(parse_html(m[1]))}else if(block_type==="###"){}else if(block_type==="pre"){list.add(["pre",pba,m[1]])}else if(re_footnote_def.test(block_type)){var fnid=block_type.replace(/\D+/g,"");if(!pba){pba={}}pba["class"]=(pba["class"]?pba["class"]+" ":"")+"footnote";pba["id"]="fn"+fnid;list.add(["p",pba,["a",{href:"#fnr"+fnid},["sup",fnid]]," "].concat(parse_inline(m[1],options)))}else{list.merge(paragraph(m[1],block_type,pba,"\n"))}continue}else{src.load()}}if(m=re_html_comment.exec(src)){src.advance(m[0]+(/(?:\s*\n+)+/.exec(src)||[])[0]);list.add(["!",m[1]]);continue}if(m=re_html_tag_block.exec(src)){var tag=m[1],single=m[3]||tag in html_singletons,tail=m[4];if(tag in allowed_blocktags){src.advance(m[0]);var element=[tag];if(m[2]){element.push(parse_html_attr(m[2]))}if(single){list.add(element);continue}else{var re_end_tag=re.compile("^(.*?)(\\s*)()(\\s*)","s");if(m=re_end_tag.exec(src)){src.advance(m[0]);if(tag==="pre"){element.push(tail);element=element.concat(parse_html(m[1].replace(/(\r?\n)+$/,""),{code:1}));if(m[2]){element.push(m[2])}list.add(element)}else if(tag==="notextile"){element=parse_html(m[1].trim());list.merge(element)}else if(tag==="script"||tag==="noscript"){element.push(tail+m[1]);list.add(element)}else{if(/\n/.test(tail)){element.push("\n")}if(/\n/.test(m[1])){element=element.concat(parse_blocks(m[1],options))}else{element=element.concat(parse_inline(m[1].replace(/^ +/,""),options))}if(/\n/.test(m[2])){element.push("\n")}list.add(element)}continue}}}src.load()}if(m=re_ruler.exec(src)){src.advance(m[0]);list.add(["hr"]);continue}if(m=re_list.exec(src)){src.advance(m[0]);list.add(parse_list(m[0],options));continue}if(m=re_deflist.exec(src)){src.advance(m[0]);list.add(parse_deflist(m[0],options));continue}if(m=re_table.exec(src)){src.advance(m[0]);list.add(parse_table(m[1],options));continue}m=re_block_normal.exec(src);list.merge(paragraph(m[1],"p",undefined,"\n"));src.advance(m[0])}return list.get().map(fix_links,link_refs)}function fix_links(jsonml){if(_isArray(jsonml)){if(jsonml[0]==="a"){var attr=jsonml[1];if(typeof attr==="object"&&"href"in attr&&attr.href in this){attr.href=this[attr.href]}}for(var i=1,l=jsonml.length;i