Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

markdown-it-multimd-table

Package Overview
Dependencies
Maintainers
1
Versions
26
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

markdown-it-multimd-table - npm Package Compare versions

Comparing version 3.2.3 to 4.0.0

lib/dfa.js

19

bower.json

@@ -24,15 +24,14 @@ {

],
"dependencies":{
"markdown-it": "^5.0.3"
"dependencies": {
"markdown-it": "^8.4.2"
},
"devDependencies": {
"browserify": "*",
"coveralls": "^2.11.2",
"eslint": "^3.19.0",
"eslint-plugin-nodeca": "^1.0.0",
"istanbul": "*",
"markdown-it-testgen": "~0.1.0",
"mocha": "*",
"uglify-js": "^2.7.3"
"browserify": "^16.3.0",
"coveralls": "^3.0.4",
"eslint": "^6.0.1",
"istanbul": "^0.4.5",
"markdown-it-testgen": "^0.1.3",
"mocha": "^6.1.4",
"terser": "^4.1.2"
}
}

@@ -1,224 +0,191 @@

/*! markdown-it-multimd-table 3.2.3 https://github.com/RedBug312/markdown-it-multimd-table @license MIT */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.markdownitMultimdTable = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
/*! markdown-it-multimd-table 4.0.0 https://github.com/RedBug312/markdown-it-multimd-table @license MIT */(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.markdownitMultimdTable = f()}})(function(){var define,module,exports;return (function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i<t.length;i++)o(t[i]);return o}return r})()({1:[function(require,module,exports){
'use strict';
module.exports = function multimd_table_plugin(md, pluginOptions) {
pluginOptions = pluginOptions || {};
// constructor
function getLine(state, line) {
var pos = state.bMarks[line] + state.blkIndent,
max = state.eMarks[line];
return state.src.slice(pos, max);
}
function DFA() {
// alphabets are encoded by numbers in 16^N form, presenting its precedence
this.__highest_alphabet__ = 0x0;
this.__match_alphabets__ = {};
// states are union (bitwise OR) of its accepted alphabets
this.__initial_state__ = 0x0;
this.__accept_states__ = {};
// transitions are in the form: {prev_state: {alphabet: next_state}}
this.__transitions__ = {};
// actions take two parameters: step (line number), prev_state and alphabet
this.__actions__ = {};
}
function escapedSplit(str) {
var result = [],
max = str.length,
lastPos = 0,
escaped = false,
backTicked = false;
// setters
for (var pos = 0; pos < max; pos++) {
switch (str.charCodeAt(pos)) {
case 0x5c /* \ */:
escaped = true;
break;
case 0x60 /* ` */:
if (backTicked || !escaped) {
/* make \` closes the code sequence, but not open it;
the reason is that `\` is correct code block */
backTicked = !backTicked;
}
escaped = false;
break;
case 0x7c /* | */:
if (!backTicked && !escaped) {
result.push(str.slice(lastPos, pos));
lastPos = pos + 1;
}
escaped = false;
break;
default:
escaped = false;
break;
}
}
DFA.prototype.set_highest_alphabet = function (alphabet) {
this.__highest_alphabet__ = alphabet;
};
result.push(str.slice(lastPos));
DFA.prototype.set_match_alphabets = function (matches) {
this.__match_alphabets__ = matches;
};
return result;
DFA.prototype.set_initial_state = function (initial) {
this.__initial_state__ = initial;
};
DFA.prototype.set_accept_states = function (accepts) {
for (var i = 0; i < accepts.length; i++) {
this.__accept_states__[accepts[i]] = true;
}
};
function countColspan(columns) {
var emptyCount = 0,
colspans = [];
DFA.prototype.set_transitions = function (transitions) {
this.__transitions__ = transitions;
};
for (var i = columns.length - 1; i >= 0; i--) {
if (columns[i]) {
colspans.unshift(emptyCount + 1);
emptyCount = 0;
} else {
emptyCount++;
}
DFA.prototype.set_actions = function (actions) {
this.__actions__ = actions;
};
DFA.prototype.update_transition = function (state, alphabets) {
this.__transitions__[state] = Object.assign(
this.__transitions__[state] || Object(), alphabets
);
};
// methods
DFA.prototype.execute = function (start, end) {
var state, step, alphabet;
for (state = this.__initial_state__, step = start; state && step < end; step++) {
for (alphabet = this.__highest_alphabet__; alphabet > 0x0; alphabet >>= 4) {
if ((state & alphabet)
&& this.__match_alphabets__[alphabet].call(this, step, state, alphabet)) { break; }
}
if (emptyCount > 0) {
colspans.unshift(emptyCount + 1);
}
return colspans;
this.__actions__(step, state, alphabet);
if (alphabet === 0x0) { break; }
state = this.__transitions__[state][alphabet] || 0x0;
}
return !!this.__accept_states__[state];
};
function caption(state, lineText, lineNum, silent) {
var result = lineText.match(/^\[([^\[\]]+)\](\[([^\[\]]+)\])?\s*$/);
if (!result) { return false; }
if (silent) { return true; }
module.exports = DFA;
var captionInfo = { caption: null, label: null };
captionInfo.content = result[1];
captionInfo.label = result[2] || result[1];
/* vim: set ts=2 sw=2 et: */
var token;
token = state.push('caption_open', 'caption', 1);
token.map = [ lineNum, lineNum + 1 ];
token.attrs = [ [ 'id', captionInfo.label.toLowerCase().replace(/\W+/g, '') ] ];
},{}],2:[function(require,module,exports){
'use strict';
var DFA = require('./lib/dfa.js');
token = state.push('inline', '', 0);
token.content = captionInfo.content;
token.map = [ lineNum, lineNum + 1 ];
token.children = [];
module.exports = function multimd_table_plugin(md, options) {
// TODO be consistent with markdown-it method
options = options || {};
token = state.push('caption_close', 'caption', -1);
function scan_bound_indices(state, line) {
var start = state.bMarks[line], /* no tShift to detect \n */
max = state.eMarks[line],
bounds = [], pos,
escape = false, code = false;
return captionInfo;
}
/* Scan for valid pipe character position */
for (pos = start; pos < max; pos++) {
switch (state.src.charCodeAt(pos)) {
case 0x5c /* \ */:
escape = true; break;
case 0x60 /* ` */:
/* make \` closes the code sequence, but not open it;
the reason is that `\` is correct code block */
if (code || !escape) { code = !code; }
if (state.src.charCodeAt(pos - 1) === 0x60) { code = false; }
escape = false; break;
case 0x7c /* | */:
if (!code && !escape) { bounds.push(pos); }
escape = false; break;
default:
escape = false; break;
}
}
if (bounds.length === 0) return bounds;
function appendRowToken(state, content, startLine, endLine) {
var linesCount, blockParser, tmpState, token;
linesCount = content.split(/\n/).length;
/* Pad in newline characters on last and this line */
if (bounds[0] > start) { bounds.unshift(start - 1); }
if (bounds[bounds.length - 1] < max - 1) { bounds.push(max); }
if (linesCount > 1) {
// Multiline content => subparsing as a block to support lists
blockParser = state.md.block;
tmpState = new blockParser.State(content, state.md, state.env, state.tokens);
blockParser.tokenize(tmpState, 0, linesCount); // appends to state.tokens
} else {
token = state.push('inline', '', 0);
token.content = content;
token.map = [ startLine, endLine ];
token.children = [];
}
return bounds;
}
function tableRow(state, lineText, lineNum, silent, separatorInfo, rowType, rowspanState) {
var rowInfo, columns;
rowInfo = { colspans: null, columns: null, extractedTextLinesCount: 1 };
columns = escapedSplit(lineText.replace(/^\||([^\\])\|$/g, '$1'));
function table_caption(state, silent, line) {
var start = state.bMarks[line] + state.tShift[line],
max = state.eMarks[line],
capRE = /^\[([^\[\]]+)\](\[([^\[\]]+)\])?\s*$/,
matches = state.src.slice(start, max).match(capRE),
meta = {};
// lineText does not contain valid pipe character
if (columns.length === 1 && !/^\||[^\\]\|$/.test(lineText)) { return false; }
if (silent) { return true; }
if (!matches) { return false; }
if (silent) { return true; }
// TODO eliminate capRE by simple checking
// Multiline feature
if (pluginOptions.enableMultilineRows && lineText.slice(-1) === '\\') {
var lineTextNext, columnsNext, EndOfMultilines;
var trimItself = Function.prototype.call.bind(String.prototype.trim); // equal to (x => x.trim())
columns = escapedSplit(lineText.replace(/\\$/, '').replace(/^\||([^\\])\|$/g, '$1'));
var initialIndent = /^\s*/.exec(columns[0])[0];
var trimRegex = new RegExp('^' + initialIndent + '|\\s+$', 'g');
columns = columns.map(trimItself);
do {
lineTextNext = getLine(state, lineNum + rowInfo.extractedTextLinesCount);
columnsNext = escapedSplit(lineTextNext.replace(/\\$/, '').replace(/^\||([^\\])\|$/g, '$1'));
EndOfMultilines = lineTextNext.slice(-1) !== '\\';
meta.text = matches[1];
meta.label = matches[2] || matches[1];
meta.label = meta.label.toLowerCase().replace(/\W+/g, '');
if (columnsNext.length === 1 && !/^\||[^\\]\|$|\\$/.test(lineTextNext)) { return false; }
if (columnsNext.length !== columns.length && !EndOfMultilines) { return false; }
return meta;
}
for (var j = 0; j < columnsNext.length; j++) {
columns[j] = columns[j] || '';
columns[j] += '\n' + columnsNext[j].replace(trimRegex, '');
}
rowInfo.extractedTextLinesCount += 1;
function table_row(state, silent, line) {
var bounds = scan_bound_indices(state, line),
meta = {}, start, pos, oldMax;
} while (!EndOfMultilines);
}
if (bounds.length < 2) { return false; }
if (silent) { return true; }
// Fill in HTML <tr> elements
var isValidColumn = RegExp.prototype.test.bind(/[^\n]/); // equal to (s => /[^\n]/.test(s))
rowInfo.columns = columns.filter(isValidColumn);
rowInfo.colspans = countColspan(columns.map(isValidColumn));
meta.bounds = bounds;
var token = state.push('tr_open', 'tr', 1);
token.map = [ lineNum, lineNum + rowInfo.extractedTextLinesCount ];
for (var i = 0, col = 0;
i < rowInfo.columns.length && col < separatorInfo.aligns.length;
col += rowInfo.colspans[i], i++) {
if (pluginOptions.enableRowspan &&
rowspanState && rowspanState[i] &&
/^\s*\^\^\s*$/.test(rowInfo.columns[i])) {
var rowspanAttr = rowspanState[i].attrs.find(function (attr) {
return attr[0] === 'rowspan';
});
if (!rowspanAttr) {
rowspanAttr = [ 'rowspan', 1 ];
rowspanState[i].attrs.push(rowspanAttr);
}
rowspanAttr[1]++;
continue;
/* Multiline. Scan boundaries again since it's very complicated */
if (options.multiline) {
start = state.bMarks[line] + state.tShift[line];
pos = state.eMarks[line] - 1; /* where backslash should be */
meta.multiline = (state.src.charCodeAt(pos) === 0x5C/* \ */);
if (meta.multiline) {
oldMax = state.eMarks[line];
state.eMarks[line] = state.skipSpacesBack(pos, start);
meta.bounds = scan_bound_indices(state, line);
state.eMarks[line] = oldMax;
}
token = state.push(rowType + '_open', rowType, 1);
token.map = [ lineNum, lineNum + rowInfo.extractedTextLinesCount ];
token.attrs = [];
rowspanState[i] = {
attrs: token.attrs
};
if (separatorInfo.aligns[col]) {
token.attrs.push([ 'style', 'text-align:' + separatorInfo.aligns[col] ]);
}
if (separatorInfo.wraps[col]) {
token.attrs.push([ 'class', 'extend' ]);
}
if (rowInfo.colspans[i] > 1) {
token.attrs.push([ 'colspan', rowInfo.colspans[i] ]);
}
appendRowToken(state, rowInfo.columns[i].trim(), lineNum, lineNum + rowInfo.extractedTextLinesCount);
token = state.push(rowType + '_close', rowType, -1);
}
state.push('tr_close', 'tr', -1);
return rowInfo;
return meta;
}
function separator(state, lineText, lineNum, silent) {
// lineText have code indentation
if (state.sCount[lineNum] - state.blkIndent >= 4) { return false; }
function table_separator(state, silent, line) {
var bounds = scan_bound_indices(state, line),
meta = { aligns: [], wraps: [] },
sepRE = /^:?(-+|=+):?\+?$/,
c, text, align;
// lineText does not contain valid pipe character
var columns = escapedSplit(lineText.replace(/^\||([^\\])\|$/g, '$1'));
if (columns.length === 1 && !/^\||[^\\]\|$/.test(lineText)) { return false; }
/* Only separator needs to check indents */
if (state.sCount[line] - state.blkIndent >= 4) { return false; }
if (bounds.length === 0) { return false; }
var separatorInfo = { aligns: [], wraps: [] };
for (c = 0; c < bounds.length - 1; c++) {
text = state.src.slice(bounds[c] + 1, bounds[c + 1]).trim();
if (!sepRE.test(text)) { return false; }
for (var i = 0; i < columns.length; i++) {
var t = columns[i].trim();
if (!/^:?(-+|=+):?\+?$/.test(t)) { return false; }
separatorInfo.wraps.push(t.charCodeAt(t.length - 1) === 0x2B/* + */);
if (separatorInfo.wraps[i]) {
t = t.slice(0, -1);
meta.wraps.push(text.charCodeAt(text.length - 1) === 0x2B/* + */);
align = ((text.charCodeAt(0) === 0x3A/* : */) << 4) |
(text.charCodeAt(text.length - 1 - meta.wraps[c]) === 0x3A);
switch (align) {
case 0x00: meta.aligns.push(''); break;
case 0x01: meta.aligns.push('right'); break;
case 0x10: meta.aligns.push('left'); break;
case 0x11: meta.aligns.push('center'); break;
}
switch (((t.charCodeAt(0) === 0x3A /* : */) << 4) +
(t.charCodeAt(t.length - 1) === 0x3A /* : */)) {
case 0x00: separatorInfo.aligns.push(''); break;
case 0x01: separatorInfo.aligns.push('right'); break;
case 0x10: separatorInfo.aligns.push('left'); break;
case 0x11: separatorInfo.aligns.push('center'); break;
}
}
if (silent) { return true; }
return meta;
}
return silent || separatorInfo;
function table_empty(state, silent, line) {
var start = state.bMarks[line] + state.tShift[line],
max = state.eMarks[line];
return start === max;
}

@@ -228,18 +195,39 @@

/* Regex pseudo code for table:
* caption? header+ separator (data+ empty)* data+ caption?
* caption? header+ separator (data+ empty)* data+ caption?
*
* We use NFA with precedences to emulate this plugin.
* Noted that separator should have higher precedence than header or data.
* We use DFA to emulate this plugin. Types with lower precedence are
* set-minus from all the formers. Noted that separator should have higher
* precedence than header or data.
* | state | caption separator header data empty | --> lower precedence
* | 0x10100 | 1 0 1 0 0 |
*/
var tableDFA = new DFA(),
grp = 0x10, mtr = -1,
token, tableToken, trToken,
colspan, leftToken,
rowspan, upTokens = [],
tableLines, tgroupLines,
tag, text, range, r, c, b;
var match = {
0x10000: function (s, l, lt) { return caption(s, lt, l, true); },
0x01000: function (s, l, lt) { return separator(s, lt, l); },
0x00100: function (s, l, lt) { return tableRow(s, lt, l, true, null, 'th'); },
0x00010: function (s, l, lt) { return tableRow(s, lt, l, true, null, 'td'); },
0x00001: function (s, l, lt) { return !lt; }
};
var transitions = {
if (startLine + 2 > endLine) { return false; }
/**
* First pass: validate and collect info into table token. IR is stored in
* markdown-it `token.meta` to be pushed later. table/tr open tokens are
* generated here.
*/
tableToken = new state.Token('table_open', 'table', 1);
tableToken.meta = { sep: null, cap: null, tr: [] };
tableDFA.set_highest_alphabet(0x10000);
tableDFA.set_initial_state(0x10100);
tableDFA.set_accept_states([ 0x10010, 0x10011, 0x00000 ]);
tableDFA.set_match_alphabets({
0x10000: table_caption.bind(this, state, true),
0x01000: table_separator.bind(this, state, true),
0x00100: table_row.bind(this, state, true),
0x00010: table_row.bind(this, state, true),
0x00001: table_empty.bind(this, state, true)
});
tableDFA.set_transitions({
0x10100: { 0x10000: 0x00100, 0x00100: 0x01100 },

@@ -250,107 +238,171 @@ 0x00100: { 0x00100: 0x01100 },

0x10011: { 0x10000: 0x00000, 0x00010: 0x10011, 0x00001: 0x10010 }
};
/* Check validity; Gather separator informations */
if (startLine + 2 > endLine) { return false; }
var NFAstate, line, candidate, rowInfo, lineText, separatorInfo;
var captionAtFirst = false;
for (NFAstate = 0x10100, line = startLine; NFAstate && line < endLine; line++) {
lineText = getLine(state, line).trim();
for (candidate = 0x10000; candidate > 0; candidate >>= 4) {
if (NFAstate & candidate && match[candidate].call(this, state, line, lineText)) { break; }
}
switch (candidate) {
});
if (options.headerless) {
tableDFA.set_initial_state(0x11100);
tableDFA.update_transition(0x11100,
{ 0x10000: 0x01100, 0x01000: 0x10010, 0x00100: 0x01100 }
);
trToken = new state.Token('table_fake_header_row', 'tr', 1);
trToken.meta = Object(); // avoid trToken.meta.grp throws exception
}
/* Don't mix up DFA `_state` and markdown-it `state` */
tableDFA.set_actions(function (_line, _state, _type) {
switch (_type) {
case 0x10000:
if (NFAstate === 0x10100) { captionAtFirst = true; }
if (tableToken.meta.cap) { break; }
tableToken.meta.cap = table_caption(state, false, _line);
tableToken.meta.cap.map = [ _line, _line + 1 ];
tableToken.meta.cap.first = (_line === startLine);
break;
case 0x01000:
separatorInfo = separator(state, lineText, line);
if (silent) { return true; }
tableToken.meta.sep = table_separator(state, false, _line);
tableToken.meta.sep.map = [ _line, _line + 1 ];
trToken.meta.grp |= 0x01; // previously assigned at case 0x00110
grp = 0x10;
break;
case 0x00100:
case 0x00010:
trToken = new state.Token('table_row_open', 'tr', 1);
trToken.map = [ _line, _line + 1 ];
trToken.meta = table_row(state, false, _line);
trToken.meta.type = _type;
trToken.meta.grp = grp;
grp = 0x00;
tableToken.meta.tr.push(trToken);
/* Multiline. Merge trTokens as an entire multiline trToken */
if (options.multiline) {
if (trToken.meta.multiline && mtr < 0) {
/* Start line of multiline row. mark this trToken */
mtr = tableToken.meta.tr.length - 1;
} else if (!trToken.meta.multiline && mtr >= 0) {
/* End line of multiline row. merge forward until the marked trToken */
token = tableToken.meta.tr[mtr];
token.meta.mbounds = tableToken.meta.tr
.slice(mtr).map(function (tk) { return tk.meta.bounds; });
token.map[1] = trToken.map[1];
tableToken.meta.tr = tableToken.meta.tr.slice(0, mtr + 1);
mtr = -1;
}
}
break;
case 0x00001:
trToken.meta.grp |= 0x01;
grp = 0x10;
break;
case 0x00000:
if (NFAstate & 0x00100) { return false; } // separator not reached
}
});
NFAstate = transitions[NFAstate][candidate] || 0x00000;
}
if (tableDFA.execute(startLine, endLine) === false) { return false; }
// if (!tableToken.meta.sep) { return false; } // always evaluated true
if (!tableToken.meta.tr.length) { return false; } // false under headerless corner case
if (silent) { return true; }
if (!separatorInfo) { return false; }
/* Last data row cannot be detected. not stored to trToken outside? */
tableToken.meta.tr[tableToken.meta.tr.length - 1].meta.grp |= 0x01;
/* Generate table HTML */
var token, tableLines, theadLines, tbodyLines;
token = state.push('table_open', 'table', 1);
token.map = tableLines = [ startLine, 0 ];
/**
* Second pass: actually push the tokens into `state.tokens`.
* thead/tbody/th/td open tokens and all closed tokens are generated here;
* thead/tbody are generally called tgroup; td/th are generally called tcol.
*/
tableToken.map = tableLines = [ startLine, 0 ];
tableToken.block = true;
tableToken.level = state.level++;
state.tokens.push(tableToken);
var rowspanState;
for (NFAstate = 0x10100, line = startLine; NFAstate && line < endLine; line++) {
lineText = getLine(state, line).trim();
if (tableToken.meta.cap) {
token = state.push('caption_open', 'caption', 1);
token.map = tableToken.meta.cap.map;
token.attrs = [ [ 'id', tableToken.meta.cap.label ] ];
for (candidate = 0x10000; candidate > 0; candidate >>= 4) {
if (NFAstate & candidate && match[candidate].call(this, state, line, lineText)) { break; }
token = state.push('inline', '', 0);
token.content = tableToken.meta.cap.text;
token.map = tableToken.meta.cap.map;
token.children = [];
token = state.push('caption_close', 'caption', -1);
}
for (r = 0; r < tableToken.meta.tr.length; r++) {
leftToken = new state.Token('table_fake_tcol_open', '', 1);
/* Push in thead/tbody and tr open tokens */
trToken = tableToken.meta.tr[r];
// console.log(trToken.meta); // for test
if (trToken.meta.grp & 0x10) {
tag = (trToken.meta.type === 0x00100) ? 'thead' : 'tbody';
token = state.push('table_group_open', tag, 1);
token.map = tgroupLines = [ trToken.map[0], 0 ]; // array ref
upTokens = [];
}
trToken.block = true;
trToken.level = state.level++;
state.tokens.push(trToken);
switch (candidate) {
case 0x10000:
if (NFAstate !== 0x10100) { // the last line in table
tbodyLines[1] = line;
token = state.push('tbody_close', 'tbody', -1);
/* Push in th/td tokens */
for (c = 0; c < trToken.meta.bounds.length - 1; c++) {
range = [ trToken.meta.bounds[c] + 1, trToken.meta.bounds[c + 1] ];
text = state.src.slice.apply(state.src, range);
if (text === '') {
colspan = leftToken.attrGet('colspan');
leftToken.attrSet('colspan', colspan === null ? 2 : colspan + 1);
continue;
}
if (options.rowspan && upTokens[c] && text.trim() === '^^') {
rowspan = upTokens[c].attrGet('rowspan');
upTokens[c].attrSet('rowspan', rowspan === null ? 2 : rowspan + 1);
continue;
}
tag = (trToken.meta.type === 0x00100) ? 'th' : 'td';
token = state.push('table_column_open', tag, 1);
token.map = trToken.map;
token.attrs = [];
if (tableToken.meta.sep.aligns[c]) {
token.attrs.push([ 'style', 'text-align:' + tableToken.meta.sep.aligns[c] ]);
}
if (tableToken.meta.sep.wraps[c]) {
token.attrs.push([ 'class', 'extend' ]);
}
leftToken = upTokens[c] = token;
/* Multiline. Join the text and feed into markdown-it blockParser. */
if (options.multiline && trToken.meta.multiline && trToken.meta.mbounds) {
text = [ text.trimRight() ];
for (b = 1; b < trToken.meta.mbounds.length; b++) {
/* Line with N bounds has cells indexed from 0 to N-2 */
if (c > trToken.meta.mbounds[b].length - 2) { continue; }
range = [ trToken.meta.mbounds[b][c] + 1, trToken.meta.mbounds[b][c + 1] ];
text.push(state.src.slice.apply(state.src, range).trimRight());
}
if (NFAstate === 0x10100 || !captionAtFirst) {
caption(state, lineText, line, false);
} else {
line--;
}
break;
case 0x01000:
theadLines[1] = line;
token = state.push('thead_close', 'thead', -1);
break;
case 0x00100:
if (NFAstate !== 0x01100) { // the first line in thead
token = state.push('thead_open', 'thead', 1);
token.map = theadLines = [ line + 1, 0 ];
rowspanState = [];
}
rowInfo = tableRow(state, lineText, line, false, separatorInfo, 'th', rowspanState);
line += rowInfo.extractedTextLinesCount - 1;
break;
case 0x00010:
if (NFAstate !== 0x10011) { // the first line in tbody
token = state.push('tbody_open', 'tbody', 1);
token.map = tbodyLines = [ line + 1, 0 ];
rowspanState = [];
}
rowInfo = tableRow(state, lineText, line, false, separatorInfo, 'td', rowspanState);
line += rowInfo.extractedTextLinesCount - 1;
break;
case 0x00001:
tbodyLines[1] = line;
token = state.push('tbody_close', 'tbody', -1);
break;
case 0x00000:
line--;
break;
state.md.block.parse(text.join('\n'), state.md, state.env, state.tokens);
} else {
token = state.push('inline', '', 0);
token.content = text.trim();
token.map = trToken.map;
token.children = [];
}
token = state.push('table_column_close', tag, -1);
}
NFAstate = transitions[NFAstate][candidate] || 0x00000;
/* Push in tr and thead/tbody closed tokens */
state.push('tr_close', 'tr', -1);
if (trToken.meta.grp & 0x01) {
tag = (trToken.meta.type === 0x00100) ? 'thead' : 'tbody';
token = state.push('table_group_close', tag, -1);
tgroupLines[1] = trToken.map[1];
}
}
if (tbodyLines && !tbodyLines[1]) { // Corner case: table without tbody or EOL
tbodyLines[1] = line;
token = state.push('tbody_close', 'tbody', -1);
}
tableLines[1] = line;
tableLines[1] = Math.max(
tgroupLines[1],
tableToken.meta.sep.map[1],
tableToken.meta.cap ? tableToken.meta.cap.map[1] : -1
);
token = state.push('table_close', 'table', -1);
state.line = line;
state.line = tableLines[1];
return true;

@@ -364,3 +416,3 @@ }

},{}]},{},[1])(1)
},{"./lib/dfa.js":1}]},{},[2])(2)
});

@@ -1,1 +0,1 @@

!function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).markdownitMultimdTable=e()}}(function(){return function e(t,n,r){function a(o,i){if(!n[o]){if(!t[o]){var l="function"==typeof require&&require;if(!i&&l)return l(o,!0);if(s)return s(o,!0);var u=new Error("Cannot find module '"+o+"'");throw u.code="MODULE_NOT_FOUND",u}var c=n[o]={exports:{}};t[o][0].call(c.exports,function(e){return a(t[o][1][e]||e)},c,c.exports,e,t,n,r)}return n[o].exports}for(var s="function"==typeof require&&require,o=0;o<r.length;o++)a(r[o]);return a}({1:[function(e,t,n){"use strict";t.exports=function(e,t){function n(e,t){var n=e.bMarks[t]+e.blkIndent,r=e.eMarks[t];return e.src.slice(n,r)}function r(e){for(var t=[],n=e.length,r=0,a=!1,s=!1,o=0;o<n;o++)switch(e.charCodeAt(o)){case 92:a=!0;break;case 96:!s&&a||(s=!s),a=!1;break;case 124:s||a||(t.push(e.slice(r,o)),r=o+1),a=!1;break;default:a=!1}return t.push(e.slice(r)),t}function a(e,t,n,r){var a=t.match(/^\[([^\[\]]+)\](\[([^\[\]]+)\])?\s*$/);if(!a)return!1;if(r)return!0;var s,o={caption:null,label:null};return o.content=a[1],o.label=a[2]||a[1],(s=e.push("caption_open","caption",1)).map=[n,n+1],s.attrs=[["id",o.label.toLowerCase().replace(/\W+/g,"")]],(s=e.push("inline","",0)).content=o.content,s.map=[n,n+1],s.children=[],s=e.push("caption_close","caption",-1),o}function s(e,t,n,r){var a,s,o,i;(a=t.split(/\n/).length)>1?(o=new(s=e.md.block).State(t,e.md,e.env,e.tokens),s.tokenize(o,0,a)):((i=e.push("inline","",0)).content=t,i.map=[n,r],i.children=[])}function o(e,a,o,i,l,u,c){var p,f;if(p={colspans:null,columns:null,extractedTextLinesCount:1},1===(f=r(a.replace(/^\||([^\\])\|$/g,"$1"))).length&&!/^\||[^\\]\|$/.test(a))return!1;if(i)return!0;if(t.enableMultilineRows&&"\\"===a.slice(-1)){var h,d,b,g=Function.prototype.call.bind(String.prototype.trim);f=r(a.replace(/\\$/,"").replace(/^\||([^\\])\|$/g,"$1"));var m=/^\s*/.exec(f[0])[0],x=new RegExp("^"+m+"|\\s+$","g");f=f.map(g);do{if(d=r((h=n(e,o+p.extractedTextLinesCount)).replace(/\\$/,"").replace(/^\||([^\\])\|$/g,"$1")),b="\\"!==h.slice(-1),1===d.length&&!/^\||[^\\]\|$|\\$/.test(h))return!1;if(d.length!==f.length&&!b)return!1;for(var v=0;v<d.length;v++)f[v]=f[v]||"",f[v]+="\n"+d[v].replace(x,"");p.extractedTextLinesCount+=1}while(!b)}var k=RegExp.prototype.test.bind(/[^\n]/);p.columns=f.filter(k),p.colspans=function(e){for(var t=0,n=[],r=e.length-1;r>=0;r--)e[r]?(n.unshift(t+1),t=0):t++;return t>0&&n.unshift(t+1),n}(f.map(k));var w=e.push("tr_open","tr",1);w.map=[o,o+p.extractedTextLinesCount];for(var y=0,$=0;y<p.columns.length&&$<l.aligns.length;$+=p.colspans[y],y++)if(t.enableRowspan&&c&&c[y]&&/^\s*\^\^\s*$/.test(p.columns[y])){var _=c[y].attrs.find(function(e){return"rowspan"===e[0]});_||(_=["rowspan",1],c[y].attrs.push(_)),_[1]++}else(w=e.push(u+"_open",u,1)).map=[o,o+p.extractedTextLinesCount],w.attrs=[],c[y]={attrs:w.attrs},l.aligns[$]&&w.attrs.push(["style","text-align:"+l.aligns[$]]),l.wraps[$]&&w.attrs.push(["class","extend"]),p.colspans[y]>1&&w.attrs.push(["colspan",p.colspans[y]]),s(e,p.columns[y].trim(),o,o+p.extractedTextLinesCount),w=e.push(u+"_close",u,-1);return e.push("tr_close","tr",-1),p}function i(e,t,n,a){if(e.sCount[n]-e.blkIndent>=4)return!1;var s=r(t.replace(/^\||([^\\])\|$/g,"$1"));if(1===s.length&&!/^\||[^\\]\|$/.test(t))return!1;for(var o={aligns:[],wraps:[]},i=0;i<s.length;i++){var l=s[i].trim();if(!/^:?(-+|=+):?\+?$/.test(l))return!1;switch(o.wraps.push(43===l.charCodeAt(l.length-1)),o.wraps[i]&&(l=l.slice(0,-1)),((58===l.charCodeAt(0))<<4)+(58===l.charCodeAt(l.length-1))){case 0:o.aligns.push("");break;case 1:o.aligns.push("right");break;case 16:o.aligns.push("left");break;case 17:o.aligns.push("center")}}return a||o}t=t||{},e.block.ruler.at("table",function(e,t,r,s){var l,u,c,p,f,h={65536:function(e,t,n){return a(e,n,t,!0)},4096:function(e,t,n){return i(e,n,t)},256:function(e,t,n){return o(e,n,t,!0,null,"th")},16:function(e,t,n){return o(e,n,t,!0,null,"td")},1:function(e,t,n){return!n}},d={65792:{65536:256,256:4352},256:{256:4352},4352:{4096:65552,256:4352},65552:{65536:0,16:65553},65553:{65536:0,16:65553,1:65552}};if(t+2>r)return!1;var b,g,m,x,v=!1;for(l=65792,u=t;l&&u<r;u++){for(p=n(e,u).trim(),c=65536;c>0&&!(l&c&&h[c].call(this,e,u,p));c>>=4);switch(c){case 65536:65792===l&&(v=!0);break;case 4096:if(f=i(e,p,u),s)return!0;break;case 256:case 16:case 1:break;case 0:if(256&l)return!1}l=d[l][c]||0}if(!f)return!1;for(e.push("table_open","table",1).map=b=[t,0],l=65792,u=t;l&&u<r;u++){for(p=n(e,u).trim(),c=65536;c>0&&!(l&c&&h[c].call(this,e,u,p));c>>=4);switch(c){case 65536:65792!==l&&(m[1]=u,e.push("tbody_close","tbody",-1)),65792!==l&&v?u--:a(e,p,u,!1);break;case 4096:g[1]=u,e.push("thead_close","thead",-1);break;case 256:4352!==l&&(e.push("thead_open","thead",1).map=g=[u+1,0],x=[]),u+=o(e,p,u,!1,f,"th",x).extractedTextLinesCount-1;break;case 16:65553!==l&&(e.push("tbody_open","tbody",1).map=m=[u+1,0],x=[]),u+=o(e,p,u,!1,f,"td",x).extractedTextLinesCount-1;break;case 1:m[1]=u,e.push("tbody_close","tbody",-1);break;case 0:u--}l=d[l][c]||0}return m&&!m[1]&&(m[1]=u,e.push("tbody_close","tbody",-1)),b[1]=u,e.push("table_close","table",-1),e.line=u,!0},{alt:["paragraph","reference"]})}},{}]},{},[1])(1)});
!function(t){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{("undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this).markdownitMultimdTable=t()}}(function(){return function t(e,a,s){function n(r,o){if(!a[r]){if(!e[r]){var p="function"==typeof require&&require;if(!o&&p)return p(r,!0);if(i)return i(r,!0);var l=new Error("Cannot find module '"+r+"'");throw l.code="MODULE_NOT_FOUND",l}var _=a[r]={exports:{}};e[r][0].call(_.exports,function(t){return n(e[r][1][t]||t)},_,_.exports,t,e,a,s)}return a[r].exports}for(var i="function"==typeof require&&require,r=0;r<s.length;r++)n(s[r]);return n}({1:[function(t,e,a){"use strict";function s(){this.__highest_alphabet__=0,this.__match_alphabets__={},this.__initial_state__=0,this.__accept_states__={},this.__transitions__={},this.__actions__={}}s.prototype.set_highest_alphabet=function(t){this.__highest_alphabet__=t},s.prototype.set_match_alphabets=function(t){this.__match_alphabets__=t},s.prototype.set_initial_state=function(t){this.__initial_state__=t},s.prototype.set_accept_states=function(t){for(var e=0;e<t.length;e++)this.__accept_states__[t[e]]=!0},s.prototype.set_transitions=function(t){this.__transitions__=t},s.prototype.set_actions=function(t){this.__actions__=t},s.prototype.update_transition=function(t,e){this.__transitions__[t]=Object.assign(this.__transitions__[t]||Object(),e)},s.prototype.execute=function(t,e){var a,s,n;for(a=this.__initial_state__,s=t;a&&s<e;s++){for(n=this.__highest_alphabet__;n>0&&!(a&n&&this.__match_alphabets__[n].call(this,s,a,n));n>>=4);if(this.__actions__(s,a,n),0===n)break;a=this.__transitions__[a][n]||0}return!!this.__accept_states__[a]},e.exports=s},{}],2:[function(t,e,a){"use strict";var s=t("./lib/dfa.js");e.exports=function(t,e){function a(t,e){var a,s=t.bMarks[e],n=t.eMarks[e],i=[],r=!1,o=!1;for(a=s;a<n;a++)switch(t.src.charCodeAt(a)){case 92:r=!0;break;case 96:!o&&r||(o=!o),96===t.src.charCodeAt(a-1)&&(o=!1),r=!1;break;case 124:o||r||i.push(a),r=!1;break;default:r=!1}return 0===i.length?i:(i[0]>s&&i.unshift(s-1),i[i.length-1]<n-1&&i.push(n),i)}function n(t,e,a){var s=t.bMarks[a]+t.tShift[a],n=t.eMarks[a],i=t.src.slice(s,n).match(/^\[([^\[\]]+)\](\[([^\[\]]+)\])?\s*$/),r={};return!!i&&(!!e||(r.text=i[1],r.label=i[2]||i[1],r.label=r.label.toLowerCase().replace(/\W+/g,""),r))}function i(t,s,n){var i,r,o,p=a(t,n),l={};return!(p.length<2)&&(!!s||(l.bounds=p,e.multiline&&(i=t.bMarks[n]+t.tShift[n],r=t.eMarks[n]-1,l.multiline=92===t.src.charCodeAt(r),l.multiline&&(o=t.eMarks[n],t.eMarks[n]=t.skipSpacesBack(r,i),l.bounds=a(t,n),t.eMarks[n]=o)),l))}function r(t,e,s){var n,i,r=a(t,s),o={aligns:[],wraps:[]},p=/^:?(-+|=+):?\+?$/;if(t.sCount[s]-t.blkIndent>=4)return!1;if(0===r.length)return!1;for(n=0;n<r.length-1;n++){if(i=t.src.slice(r[n]+1,r[n+1]).trim(),!p.test(i))return!1;switch(o.wraps.push(43===i.charCodeAt(i.length-1)),(58===i.charCodeAt(0))<<4|58===i.charCodeAt(i.length-1-o.wraps[n])){case 0:o.aligns.push("");break;case 1:o.aligns.push("right");break;case 16:o.aligns.push("left");break;case 17:o.aligns.push("center")}}return!!e||o}function o(t,e,a){return t.bMarks[a]+t.tShift[a]===t.eMarks[a]}e=e||{},t.block.ruler.at("table",function(t,a,p,l){var _,c,u,h,m,f,b,d,g,k,w,y,v,x,M=new s,C=16,j=-1,A=[];if(a+2>p)return!1;if((c=new t.Token("table_open","table",1)).meta={sep:null,cap:null,tr:[]},M.set_highest_alphabet(65536),M.set_initial_state(65792),M.set_accept_states([65552,65553,0]),M.set_match_alphabets({65536:n.bind(this,t,!0),4096:r.bind(this,t,!0),256:i.bind(this,t,!0),16:i.bind(this,t,!0),1:o.bind(this,t,!0)}),M.set_transitions({65792:{65536:256,256:4352},256:{256:4352},4352:{4096:65552,256:4352},65552:{65536:0,16:65553},65553:{65536:0,16:65553,1:65552}}),e.headerless&&(M.set_initial_state(69888),M.update_transition(69888,{65536:4352,4096:65552,256:4352}),(u=new t.Token("table_fake_header_row","tr",1)).meta=Object()),M.set_actions(function(s,o,p){switch(p){case 65536:if(c.meta.cap)break;c.meta.cap=n(t,!1,s),c.meta.cap.map=[s,s+1],c.meta.cap.first=s===a;break;case 4096:c.meta.sep=r(t,!1,s),c.meta.sep.map=[s,s+1],u.meta.grp|=1,C=16;break;case 256:case 16:(u=new t.Token("table_row_open","tr",1)).map=[s,s+1],u.meta=i(t,!1,s),u.meta.type=p,u.meta.grp=C,C=0,c.meta.tr.push(u),e.multiline&&(u.meta.multiline&&j<0?j=c.meta.tr.length-1:!u.meta.multiline&&j>=0&&((_=c.meta.tr[j]).meta.mbounds=c.meta.tr.slice(j).map(function(t){return t.meta.bounds}),_.map[1]=u.map[1],c.meta.tr=c.meta.tr.slice(0,j+1),j=-1));break;case 1:u.meta.grp|=1,C=16}}),!1===M.execute(a,p))return!1;if(!c.meta.tr.length)return!1;if(l)return!0;for(c.meta.tr[c.meta.tr.length-1].meta.grp|=1,c.map=b=[a,0],c.block=!0,c.level=t.level++,t.tokens.push(c),c.meta.cap&&((_=t.push("caption_open","caption",1)).map=c.meta.cap.map,_.attrs=[["id",c.meta.cap.label]],(_=t.push("inline","",0)).content=c.meta.cap.text,_.map=c.meta.cap.map,_.children=[],_=t.push("caption_close","caption",-1)),y=0;y<c.meta.tr.length;y++){for(m=new t.Token("table_fake_tcol_open","",1),16&(u=c.meta.tr[y]).meta.grp&&(g=256===u.meta.type?"thead":"tbody",(_=t.push("table_group_open",g,1)).map=d=[u.map[0],0],A=[]),u.block=!0,u.level=t.level++,t.tokens.push(u),v=0;v<u.meta.bounds.length-1;v++)if(w=[u.meta.bounds[v]+1,u.meta.bounds[v+1]],""!==(k=t.src.slice.apply(t.src,w)))if(e.rowspan&&A[v]&&"^^"===k.trim())f=A[v].attrGet("rowspan"),A[v].attrSet("rowspan",null===f?2:f+1);else{if(g=256===u.meta.type?"th":"td",(_=t.push("table_column_open",g,1)).map=u.map,_.attrs=[],c.meta.sep.aligns[v]&&_.attrs.push(["style","text-align:"+c.meta.sep.aligns[v]]),c.meta.sep.wraps[v]&&_.attrs.push(["class","extend"]),m=A[v]=_,e.multiline&&u.meta.multiline&&u.meta.mbounds){for(k=[k.trimRight()],x=1;x<u.meta.mbounds.length;x++)v>u.meta.mbounds[x].length-2||(w=[u.meta.mbounds[x][v]+1,u.meta.mbounds[x][v+1]],k.push(t.src.slice.apply(t.src,w).trimRight()));t.md.block.parse(k.join("\n"),t.md,t.env,t.tokens)}else(_=t.push("inline","",0)).content=k.trim(),_.map=u.map,_.children=[];_=t.push("table_column_close",g,-1)}else h=m.attrGet("colspan"),m.attrSet("colspan",null===h?2:h+1);t.push("tr_close","tr",-1),1&u.meta.grp&&(g=256===u.meta.type?"thead":"tbody",_=t.push("table_group_close",g,-1),d[1]=u.map[1])}return b[1]=Math.max(d[1],c.meta.sep.map[1],c.meta.cap?c.meta.cap.map[1]:-1),_=t.push("table_close","table",-1),t.line=b[1],!0},{alt:["paragraph","reference"]})}},{"./lib/dfa.js":1}]},{},[2])(2)});
'use strict';
var DFA = require('./lib/dfa.js');
module.exports = function multimd_table_plugin(md, pluginOptions) {
pluginOptions = pluginOptions || {};
module.exports = function multimd_table_plugin(md, options) {
// TODO be consistent with markdown-it method
options = options || {};
function getLine(state, line) {
var pos = state.bMarks[line] + state.blkIndent,
max = state.eMarks[line];
return state.src.slice(pos, max);
}
function scan_bound_indices(state, line) {
var start = state.bMarks[line], /* no tShift to detect \n */
max = state.eMarks[line],
bounds = [], pos,
escape = false, code = false;
function escapedSplit(str) {
var result = [],
max = str.length,
lastPos = 0,
escaped = false,
backTicked = false;
for (var pos = 0; pos < max; pos++) {
switch (str.charCodeAt(pos)) {
/* Scan for valid pipe character position */
for (pos = start; pos < max; pos++) {
switch (state.src.charCodeAt(pos)) {
case 0x5c /* \ */:
escaped = true;
break;
escape = true; break;
case 0x60 /* ` */:
if (backTicked || !escaped) {
/* make \` closes the code sequence, but not open it;
the reason is that `\` is correct code block */
backTicked = !backTicked;
}
escaped = false;
break;
/* make \` closes the code sequence, but not open it;
the reason is that `\` is correct code block */
if (code || !escape) { code = !code; }
if (state.src.charCodeAt(pos - 1) === 0x60) { code = false; }
escape = false; break;
case 0x7c /* | */:
if (!backTicked && !escaped) {
result.push(str.slice(lastPos, pos));
lastPos = pos + 1;
}
escaped = false;
break;
if (!code && !escape) { bounds.push(pos); }
escape = false; break;
default:
escaped = false;
break;
escape = false; break;
}
}
if (bounds.length === 0) return bounds;
result.push(str.slice(lastPos));
/* Pad in newline characters on last and this line */
if (bounds[0] > start) { bounds.unshift(start - 1); }
if (bounds[bounds.length - 1] < max - 1) { bounds.push(max); }
return result;
return bounds;
}
function countColspan(columns) {
var emptyCount = 0,
colspans = [];
function table_caption(state, silent, line) {
var start = state.bMarks[line] + state.tShift[line],
max = state.eMarks[line],
capRE = /^\[([^\[\]]+)\](\[([^\[\]]+)\])?\s*$/,
matches = state.src.slice(start, max).match(capRE),
meta = {};
for (var i = columns.length - 1; i >= 0; i--) {
if (columns[i]) {
colspans.unshift(emptyCount + 1);
emptyCount = 0;
} else {
emptyCount++;
}
}
if (emptyCount > 0) {
colspans.unshift(emptyCount + 1);
}
return colspans;
}
function caption(state, lineText, lineNum, silent) {
var result = lineText.match(/^\[([^\[\]]+)\](\[([^\[\]]+)\])?\s*$/);
if (!result) { return false; }
if (!matches) { return false; }
if (silent) { return true; }
// TODO eliminate capRE by simple checking
var captionInfo = { caption: null, label: null };
captionInfo.content = result[1];
captionInfo.label = result[2] || result[1];
meta.text = matches[1];
meta.label = matches[2] || matches[1];
meta.label = meta.label.toLowerCase().replace(/\W+/g, '');
var token;
token = state.push('caption_open', 'caption', 1);
token.map = [ lineNum, lineNum + 1 ];
token.attrs = [ [ 'id', captionInfo.label.toLowerCase().replace(/\W+/g, '') ] ];
token = state.push('inline', '', 0);
token.content = captionInfo.content;
token.map = [ lineNum, lineNum + 1 ];
token.children = [];
token = state.push('caption_close', 'caption', -1);
return captionInfo;
return meta;
}
function appendRowToken(state, content, startLine, endLine) {
var linesCount, blockParser, tmpState, token;
linesCount = content.split(/\n/).length;
function table_row(state, silent, line) {
var bounds = scan_bound_indices(state, line),
meta = {}, start, pos, oldMax;
if (linesCount > 1) {
// Multiline content => subparsing as a block to support lists
blockParser = state.md.block;
tmpState = new blockParser.State(content, state.md, state.env, state.tokens);
blockParser.tokenize(tmpState, 0, linesCount); // appends to state.tokens
} else {
token = state.push('inline', '', 0);
token.content = content;
token.map = [ startLine, endLine ];
token.children = [];
}
}
function tableRow(state, lineText, lineNum, silent, separatorInfo, rowType, rowspanState) {
var rowInfo, columns;
rowInfo = { colspans: null, columns: null, extractedTextLinesCount: 1 };
columns = escapedSplit(lineText.replace(/^\||([^\\])\|$/g, '$1'));
// lineText does not contain valid pipe character
if (columns.length === 1 && !/^\||[^\\]\|$/.test(lineText)) { return false; }
if (bounds.length < 2) { return false; }
if (silent) { return true; }
// Multiline feature
if (pluginOptions.enableMultilineRows && lineText.slice(-1) === '\\') {
var lineTextNext, columnsNext, EndOfMultilines;
var trimItself = Function.prototype.call.bind(String.prototype.trim); // equal to (x => x.trim())
columns = escapedSplit(lineText.replace(/\\$/, '').replace(/^\||([^\\])\|$/g, '$1'));
var initialIndent = /^\s*/.exec(columns[0])[0];
var trimRegex = new RegExp('^' + initialIndent + '|\\s+$', 'g');
columns = columns.map(trimItself);
do {
lineTextNext = getLine(state, lineNum + rowInfo.extractedTextLinesCount);
columnsNext = escapedSplit(lineTextNext.replace(/\\$/, '').replace(/^\||([^\\])\|$/g, '$1'));
EndOfMultilines = lineTextNext.slice(-1) !== '\\';
meta.bounds = bounds;
if (columnsNext.length === 1 && !/^\||[^\\]\|$|\\$/.test(lineTextNext)) { return false; }
if (columnsNext.length !== columns.length && !EndOfMultilines) { return false; }
for (var j = 0; j < columnsNext.length; j++) {
columns[j] = columns[j] || '';
columns[j] += '\n' + columnsNext[j].replace(trimRegex, '');
}
rowInfo.extractedTextLinesCount += 1;
} while (!EndOfMultilines);
}
// Fill in HTML <tr> elements
var isValidColumn = RegExp.prototype.test.bind(/[^\n]/); // equal to (s => /[^\n]/.test(s))
rowInfo.columns = columns.filter(isValidColumn);
rowInfo.colspans = countColspan(columns.map(isValidColumn));
var token = state.push('tr_open', 'tr', 1);
token.map = [ lineNum, lineNum + rowInfo.extractedTextLinesCount ];
for (var i = 0, col = 0;
i < rowInfo.columns.length && col < separatorInfo.aligns.length;
col += rowInfo.colspans[i], i++) {
if (pluginOptions.enableRowspan &&
rowspanState && rowspanState[i] &&
/^\s*\^\^\s*$/.test(rowInfo.columns[i])) {
var rowspanAttr = rowspanState[i].attrs.find(function (attr) {
return attr[0] === 'rowspan';
});
if (!rowspanAttr) {
rowspanAttr = [ 'rowspan', 1 ];
rowspanState[i].attrs.push(rowspanAttr);
}
rowspanAttr[1]++;
continue;
/* Multiline. Scan boundaries again since it's very complicated */
if (options.multiline) {
start = state.bMarks[line] + state.tShift[line];
pos = state.eMarks[line] - 1; /* where backslash should be */
meta.multiline = (state.src.charCodeAt(pos) === 0x5C/* \ */);
if (meta.multiline) {
oldMax = state.eMarks[line];
state.eMarks[line] = state.skipSpacesBack(pos, start);
meta.bounds = scan_bound_indices(state, line);
state.eMarks[line] = oldMax;
}
token = state.push(rowType + '_open', rowType, 1);
token.map = [ lineNum, lineNum + rowInfo.extractedTextLinesCount ];
token.attrs = [];
rowspanState[i] = {
attrs: token.attrs
};
if (separatorInfo.aligns[col]) {
token.attrs.push([ 'style', 'text-align:' + separatorInfo.aligns[col] ]);
}
if (separatorInfo.wraps[col]) {
token.attrs.push([ 'class', 'extend' ]);
}
if (rowInfo.colspans[i] > 1) {
token.attrs.push([ 'colspan', rowInfo.colspans[i] ]);
}
appendRowToken(state, rowInfo.columns[i].trim(), lineNum, lineNum + rowInfo.extractedTextLinesCount);
token = state.push(rowType + '_close', rowType, -1);
}
state.push('tr_close', 'tr', -1);
return rowInfo;
return meta;
}
function separator(state, lineText, lineNum, silent) {
// lineText have code indentation
if (state.sCount[lineNum] - state.blkIndent >= 4) { return false; }
function table_separator(state, silent, line) {
var bounds = scan_bound_indices(state, line),
meta = { aligns: [], wraps: [] },
sepRE = /^:?(-+|=+):?\+?$/,
c, text, align;
// lineText does not contain valid pipe character
var columns = escapedSplit(lineText.replace(/^\||([^\\])\|$/g, '$1'));
if (columns.length === 1 && !/^\||[^\\]\|$/.test(lineText)) { return false; }
/* Only separator needs to check indents */
if (state.sCount[line] - state.blkIndent >= 4) { return false; }
if (bounds.length === 0) { return false; }
var separatorInfo = { aligns: [], wraps: [] };
for (c = 0; c < bounds.length - 1; c++) {
text = state.src.slice(bounds[c] + 1, bounds[c + 1]).trim();
if (!sepRE.test(text)) { return false; }
for (var i = 0; i < columns.length; i++) {
var t = columns[i].trim();
if (!/^:?(-+|=+):?\+?$/.test(t)) { return false; }
separatorInfo.wraps.push(t.charCodeAt(t.length - 1) === 0x2B/* + */);
if (separatorInfo.wraps[i]) {
t = t.slice(0, -1);
meta.wraps.push(text.charCodeAt(text.length - 1) === 0x2B/* + */);
align = ((text.charCodeAt(0) === 0x3A/* : */) << 4) |
(text.charCodeAt(text.length - 1 - meta.wraps[c]) === 0x3A);
switch (align) {
case 0x00: meta.aligns.push(''); break;
case 0x01: meta.aligns.push('right'); break;
case 0x10: meta.aligns.push('left'); break;
case 0x11: meta.aligns.push('center'); break;
}
switch (((t.charCodeAt(0) === 0x3A /* : */) << 4) +
(t.charCodeAt(t.length - 1) === 0x3A /* : */)) {
case 0x00: separatorInfo.aligns.push(''); break;
case 0x01: separatorInfo.aligns.push('right'); break;
case 0x10: separatorInfo.aligns.push('left'); break;
case 0x11: separatorInfo.aligns.push('center'); break;
}
}
if (silent) { return true; }
return meta;
}
return silent || separatorInfo;
function table_empty(state, silent, line) {
var start = state.bMarks[line] + state.tShift[line],
max = state.eMarks[line];
return start === max;
}

@@ -227,18 +120,39 @@

/* Regex pseudo code for table:
* caption? header+ separator (data+ empty)* data+ caption?
* caption? header+ separator (data+ empty)* data+ caption?
*
* We use NFA with precedences to emulate this plugin.
* Noted that separator should have higher precedence than header or data.
* We use DFA to emulate this plugin. Types with lower precedence are
* set-minus from all the formers. Noted that separator should have higher
* precedence than header or data.
* | state | caption separator header data empty | --> lower precedence
* | 0x10100 | 1 0 1 0 0 |
*/
var tableDFA = new DFA(),
grp = 0x10, mtr = -1,
token, tableToken, trToken,
colspan, leftToken,
rowspan, upTokens = [],
tableLines, tgroupLines,
tag, text, range, r, c, b;
var match = {
0x10000: function (s, l, lt) { return caption(s, lt, l, true); },
0x01000: function (s, l, lt) { return separator(s, lt, l); },
0x00100: function (s, l, lt) { return tableRow(s, lt, l, true, null, 'th'); },
0x00010: function (s, l, lt) { return tableRow(s, lt, l, true, null, 'td'); },
0x00001: function (s, l, lt) { return !lt; }
};
var transitions = {
if (startLine + 2 > endLine) { return false; }
/**
* First pass: validate and collect info into table token. IR is stored in
* markdown-it `token.meta` to be pushed later. table/tr open tokens are
* generated here.
*/
tableToken = new state.Token('table_open', 'table', 1);
tableToken.meta = { sep: null, cap: null, tr: [] };
tableDFA.set_highest_alphabet(0x10000);
tableDFA.set_initial_state(0x10100);
tableDFA.set_accept_states([ 0x10010, 0x10011, 0x00000 ]);
tableDFA.set_match_alphabets({
0x10000: table_caption.bind(this, state, true),
0x01000: table_separator.bind(this, state, true),
0x00100: table_row.bind(this, state, true),
0x00010: table_row.bind(this, state, true),
0x00001: table_empty.bind(this, state, true)
});
tableDFA.set_transitions({
0x10100: { 0x10000: 0x00100, 0x00100: 0x01100 },

@@ -249,107 +163,171 @@ 0x00100: { 0x00100: 0x01100 },

0x10011: { 0x10000: 0x00000, 0x00010: 0x10011, 0x00001: 0x10010 }
};
/* Check validity; Gather separator informations */
if (startLine + 2 > endLine) { return false; }
var NFAstate, line, candidate, rowInfo, lineText, separatorInfo;
var captionAtFirst = false;
for (NFAstate = 0x10100, line = startLine; NFAstate && line < endLine; line++) {
lineText = getLine(state, line).trim();
for (candidate = 0x10000; candidate > 0; candidate >>= 4) {
if (NFAstate & candidate && match[candidate].call(this, state, line, lineText)) { break; }
}
switch (candidate) {
});
if (options.headerless) {
tableDFA.set_initial_state(0x11100);
tableDFA.update_transition(0x11100,
{ 0x10000: 0x01100, 0x01000: 0x10010, 0x00100: 0x01100 }
);
trToken = new state.Token('table_fake_header_row', 'tr', 1);
trToken.meta = Object(); // avoid trToken.meta.grp throws exception
}
/* Don't mix up DFA `_state` and markdown-it `state` */
tableDFA.set_actions(function (_line, _state, _type) {
switch (_type) {
case 0x10000:
if (NFAstate === 0x10100) { captionAtFirst = true; }
if (tableToken.meta.cap) { break; }
tableToken.meta.cap = table_caption(state, false, _line);
tableToken.meta.cap.map = [ _line, _line + 1 ];
tableToken.meta.cap.first = (_line === startLine);
break;
case 0x01000:
separatorInfo = separator(state, lineText, line);
if (silent) { return true; }
tableToken.meta.sep = table_separator(state, false, _line);
tableToken.meta.sep.map = [ _line, _line + 1 ];
trToken.meta.grp |= 0x01; // previously assigned at case 0x00110
grp = 0x10;
break;
case 0x00100:
case 0x00010:
trToken = new state.Token('table_row_open', 'tr', 1);
trToken.map = [ _line, _line + 1 ];
trToken.meta = table_row(state, false, _line);
trToken.meta.type = _type;
trToken.meta.grp = grp;
grp = 0x00;
tableToken.meta.tr.push(trToken);
/* Multiline. Merge trTokens as an entire multiline trToken */
if (options.multiline) {
if (trToken.meta.multiline && mtr < 0) {
/* Start line of multiline row. mark this trToken */
mtr = tableToken.meta.tr.length - 1;
} else if (!trToken.meta.multiline && mtr >= 0) {
/* End line of multiline row. merge forward until the marked trToken */
token = tableToken.meta.tr[mtr];
token.meta.mbounds = tableToken.meta.tr
.slice(mtr).map(function (tk) { return tk.meta.bounds; });
token.map[1] = trToken.map[1];
tableToken.meta.tr = tableToken.meta.tr.slice(0, mtr + 1);
mtr = -1;
}
}
break;
case 0x00001:
trToken.meta.grp |= 0x01;
grp = 0x10;
break;
case 0x00000:
if (NFAstate & 0x00100) { return false; } // separator not reached
}
});
NFAstate = transitions[NFAstate][candidate] || 0x00000;
}
if (tableDFA.execute(startLine, endLine) === false) { return false; }
// if (!tableToken.meta.sep) { return false; } // always evaluated true
if (!tableToken.meta.tr.length) { return false; } // false under headerless corner case
if (silent) { return true; }
if (!separatorInfo) { return false; }
/* Last data row cannot be detected. not stored to trToken outside? */
tableToken.meta.tr[tableToken.meta.tr.length - 1].meta.grp |= 0x01;
/* Generate table HTML */
var token, tableLines, theadLines, tbodyLines;
token = state.push('table_open', 'table', 1);
token.map = tableLines = [ startLine, 0 ];
/**
* Second pass: actually push the tokens into `state.tokens`.
* thead/tbody/th/td open tokens and all closed tokens are generated here;
* thead/tbody are generally called tgroup; td/th are generally called tcol.
*/
tableToken.map = tableLines = [ startLine, 0 ];
tableToken.block = true;
tableToken.level = state.level++;
state.tokens.push(tableToken);
var rowspanState;
for (NFAstate = 0x10100, line = startLine; NFAstate && line < endLine; line++) {
lineText = getLine(state, line).trim();
if (tableToken.meta.cap) {
token = state.push('caption_open', 'caption', 1);
token.map = tableToken.meta.cap.map;
token.attrs = [ [ 'id', tableToken.meta.cap.label ] ];
for (candidate = 0x10000; candidate > 0; candidate >>= 4) {
if (NFAstate & candidate && match[candidate].call(this, state, line, lineText)) { break; }
token = state.push('inline', '', 0);
token.content = tableToken.meta.cap.text;
token.map = tableToken.meta.cap.map;
token.children = [];
token = state.push('caption_close', 'caption', -1);
}
for (r = 0; r < tableToken.meta.tr.length; r++) {
leftToken = new state.Token('table_fake_tcol_open', '', 1);
/* Push in thead/tbody and tr open tokens */
trToken = tableToken.meta.tr[r];
// console.log(trToken.meta); // for test
if (trToken.meta.grp & 0x10) {
tag = (trToken.meta.type === 0x00100) ? 'thead' : 'tbody';
token = state.push('table_group_open', tag, 1);
token.map = tgroupLines = [ trToken.map[0], 0 ]; // array ref
upTokens = [];
}
trToken.block = true;
trToken.level = state.level++;
state.tokens.push(trToken);
switch (candidate) {
case 0x10000:
if (NFAstate !== 0x10100) { // the last line in table
tbodyLines[1] = line;
token = state.push('tbody_close', 'tbody', -1);
/* Push in th/td tokens */
for (c = 0; c < trToken.meta.bounds.length - 1; c++) {
range = [ trToken.meta.bounds[c] + 1, trToken.meta.bounds[c + 1] ];
text = state.src.slice.apply(state.src, range);
if (text === '') {
colspan = leftToken.attrGet('colspan');
leftToken.attrSet('colspan', colspan === null ? 2 : colspan + 1);
continue;
}
if (options.rowspan && upTokens[c] && text.trim() === '^^') {
rowspan = upTokens[c].attrGet('rowspan');
upTokens[c].attrSet('rowspan', rowspan === null ? 2 : rowspan + 1);
continue;
}
tag = (trToken.meta.type === 0x00100) ? 'th' : 'td';
token = state.push('table_column_open', tag, 1);
token.map = trToken.map;
token.attrs = [];
if (tableToken.meta.sep.aligns[c]) {
token.attrs.push([ 'style', 'text-align:' + tableToken.meta.sep.aligns[c] ]);
}
if (tableToken.meta.sep.wraps[c]) {
token.attrs.push([ 'class', 'extend' ]);
}
leftToken = upTokens[c] = token;
/* Multiline. Join the text and feed into markdown-it blockParser. */
if (options.multiline && trToken.meta.multiline && trToken.meta.mbounds) {
text = [ text.trimRight() ];
for (b = 1; b < trToken.meta.mbounds.length; b++) {
/* Line with N bounds has cells indexed from 0 to N-2 */
if (c > trToken.meta.mbounds[b].length - 2) { continue; }
range = [ trToken.meta.mbounds[b][c] + 1, trToken.meta.mbounds[b][c + 1] ];
text.push(state.src.slice.apply(state.src, range).trimRight());
}
if (NFAstate === 0x10100 || !captionAtFirst) {
caption(state, lineText, line, false);
} else {
line--;
}
break;
case 0x01000:
theadLines[1] = line;
token = state.push('thead_close', 'thead', -1);
break;
case 0x00100:
if (NFAstate !== 0x01100) { // the first line in thead
token = state.push('thead_open', 'thead', 1);
token.map = theadLines = [ line + 1, 0 ];
rowspanState = [];
}
rowInfo = tableRow(state, lineText, line, false, separatorInfo, 'th', rowspanState);
line += rowInfo.extractedTextLinesCount - 1;
break;
case 0x00010:
if (NFAstate !== 0x10011) { // the first line in tbody
token = state.push('tbody_open', 'tbody', 1);
token.map = tbodyLines = [ line + 1, 0 ];
rowspanState = [];
}
rowInfo = tableRow(state, lineText, line, false, separatorInfo, 'td', rowspanState);
line += rowInfo.extractedTextLinesCount - 1;
break;
case 0x00001:
tbodyLines[1] = line;
token = state.push('tbody_close', 'tbody', -1);
break;
case 0x00000:
line--;
break;
state.md.block.parse(text.join('\n'), state.md, state.env, state.tokens);
} else {
token = state.push('inline', '', 0);
token.content = text.trim();
token.map = trToken.map;
token.children = [];
}
token = state.push('table_column_close', tag, -1);
}
NFAstate = transitions[NFAstate][candidate] || 0x00000;
/* Push in tr and thead/tbody closed tokens */
state.push('tr_close', 'tr', -1);
if (trToken.meta.grp & 0x01) {
tag = (trToken.meta.type === 0x00100) ? 'thead' : 'tbody';
token = state.push('table_group_close', tag, -1);
tgroupLines[1] = trToken.map[1];
}
}
if (tbodyLines && !tbodyLines[1]) { // Corner case: table without tbody or EOL
tbodyLines[1] = line;
token = state.push('tbody_close', 'tbody', -1);
}
tableLines[1] = line;
tableLines[1] = Math.max(
tgroupLines[1],
tableToken.meta.sep.map[1],
tableToken.meta.cap ? tableToken.meta.cap.map[1] : -1
);
token = state.push('table_close', 'table', -1);
state.line = line;
state.line = tableLines[1];
return true;

@@ -356,0 +334,0 @@ }

{
"name": "markdown-it-multimd-table",
"version": "3.2.3",
"version": "4.0.0",
"description": "Multimarkdown table syntax plugin for markdown-it markdown parser",

@@ -5,0 +5,0 @@ "keywords": [

@@ -8,20 +8,35 @@ [![NPM version](https://img.shields.io/npm/v/markdown-it-multimd-table.svg?style=flat)](https://www.npmjs.org/package/markdown-it-multimd-table)

## Intro
In general Markdown syntax, we have to write raw HTML tags when `colspan` attribute is needed. Luckily, I found that [MultiMarkdown](https://fletcher.github.io/MultiMarkdown-6/) had defined complete and clear rules for advanced Markdown table syntax, and compatible to general Markdown table syntax.
When writing table in Markdown syntax, we have to fallback to write raw HTML tags, if we just need some advanced attribute like `colspan`.
[MultiMarkdown](https://fletcher.github.io/MultiMarkdown-6/) is an extended Markdown spec covering fancy features.
It has defined some complete and clear rules for advanced Markdown table syntax, and aims to be compatible to basic table syntax as possible.
So I extend the table parser in markdown-it to support MultiMarkdown table syntax. For now, the following features are provided:
[markdown-it](https://markdown-it.github.io/) is a powerful and widely-used Markdown compiler, in native it supports basic table syntax only.
It allows plugins to expand it capability, and this plugin replaced the original table parser in markdown-it to support MultiMarkdown table syntax.
For now, these extended features are provided:
- Cells spanning multiple columns
- Cells spanning multiple rows (optional)
- Grouped table headers
- Grouped table rows
- Table captions
- Lists in table cell (optional)
- Line breaks in table cells (optional)
- Grouped table header rows or data rows
- Table caption above or below the table
- Blocked elements (lists, codes, paragraphs...) in table (optional)
- Table header not required (optional)
Noted that the plugin might behave differently from MultiMarkdown in some edge cases; since the plugin aims just to follow the rules in [MultiMarkdown User's Guide](http://fletcher.github.io/MultiMarkdown-5/tables).
Noted: the plugin is not a re-written of MultiMarkdown to deploy on markdown-it, it will generate HTML different from MultiMarkdown official compiler in some corner cases.
This plugin try to follow the rule defined in [MultiMarkdown User's Guide](http://fletcher.github.io/MultiMarkdown-5/tables) as possible.
If some case is reasonable but behaves strangely, please pose an issue for that.
## Usage
```javascript
// defaults
var md = require('markdown-it')()
.use(require('markdown-it-multimd-table'));
// full options list (same to defaults)
var md = require('markdown-it')()
.use(require('markdown-it-multimd-table'), {
multiline: false,
rowspan: false,
headerless: false,
});
md.render(/*...*/)

@@ -63,8 +78,8 @@ ```

<th></th>
<th style="text-align:center" colspan="2">Grouping</th>
<th align="center" colspan="2">Grouping</th>
</tr>
<tr>
<th>First Header</th>
<th style="text-align:center">Second Header</th>
<th style="text-align:right">Third Header</th>
<th align="center">Second Header</th>
<th align="right">Third Header</th>
</tr>

@@ -75,8 +90,8 @@ </thead>

<td>Content</td>
<td style="text-align:center" colspan="2"><em>Long Cell</em></td>
<td align="center" colspan="2"><em>Long Cell</em></td>
</tr>
<tr>
<td>Content</td>
<td style="text-align:center"><strong>Cell</strong></td>
<td style="text-align:right">Cell</td>
<td align="center"><strong>Cell</strong></td>
<td align="right">Cell</td>
</tr>

@@ -87,8 +102,8 @@ </tbody>

<td>New section</td>
<td style="text-align:center">More</td>
<td style="text-align:right">Data</td>
<td align="center">More</td>
<td align="right">Data</td>
</tr>
<tr>
<td>And more</td>
<td style="text-align:center" colspan="2">With an escaped '|'</td>
<td align="center" colspan="2">With an escaped '|'</td>
</tr>

@@ -99,17 +114,24 @@ </tbody>

### Multiple lines of row (optional)
Noted that GitHub filters out `style` property, so the example displays with
the obsolete `align` property. But in actual this plugin outputs `style`
property with `text-align` CSS attribute.
Put backslashes at end to make the table rows parsed as multiple lines.
### Multiline (optional)
A backslash at end to join cell contents with the following lines.<br>
This feature is contributed by [Lucas-C](https://github.com/Lucas-C).
```markdown
First header | Second header
-------------|---------------
List: | More \
- over | data \
- several | \
- lines |
| Markdown | Rendered HTML |
|--------------|---------------|
| *Italic* | *Italic* | \
| | |
| - Item 1 | - Item 1 | \
| - Item 2 | - Item 2 |
| ```python | ```python \
| .1 + .2 | .1 + .2 \
| ``` | ``` |
```
would be parsed as
If this option is enabled, code above would be parsed as:

@@ -119,4 +141,4 @@ <table>

<tr>
<th>First header</th>
<th>Second header</th>
<th>Markdown</th>
<th>Rendered HTML</th>
</tr>

@@ -127,13 +149,31 @@ </thead>

<td>
<p>List:</p>
<pre><code>*Italic*
</code></pre>
</td>
<td>
<p><em>Italic</em></p>
</td>
</tr>
<tr>
<td>
<pre><code>- Item 1
- Item 2</code></pre>
</td>
<td>
<ul>
<li>over</li>
<li>several</li>
<li>lines</li>
<li>Item 1</li>
<li>Item 2</li>
</ul>
</td>
</tr>
<tr>
<td>
<p>More
data</p>
<pre><code>```python
.1 + .2
```</code></pre>
</td>
<td>
<pre><code class="language-python">.1 + .2
</code></pre>
</td>
</tr>

@@ -143,29 +183,29 @@ </tbody>

And here's how you enable the feature.
```javascript
var md = require('markdown-it')()
.use(require('markdown-it-multimd-table'), {enableMultilineRows: true});
```
### Rowspan (optional)
To create cells with a rowspan mark the cells to merge up with `^^`.
`^^` in a cell indicates it should be merged with the cell above.<br>
This feature is contributed by [pmccloghrylaing](https://github.com/pmccloghrylaing).
```markdown
First header | Second header
-------------|---------------
Merged | Cell 1
^^ | Cell 2
^^ | Cell 3
Stage | Direct Products | ATP Yields
----: | --------------: | ---------:
Glycolysis | 2 ATP ||
^^ | 2 NADH | 3--5 ATP |
Pyruvaye oxidation | 2 NADH | 5 ATP |
Citric acid cycle | 2 ATP ||
^^ | 6 NADH | 15 ATP |
^^ | 2 FADH2 | 3 ATP |
**30--32** ATP |||
[Net ATP yields per hexose]
```
would be parsed as
If this option is enabled, code above would be parsed as:
<table>
<caption id="netatpyieldsperhexose">Net ATP yields per hexose</caption>
<thead>
<tr>
<th>First header</th>
<th>Second header</th>
<th align="right">Stage</th>
<th align="right">Direct Products</th>
<th align="right">ATP Yields</th>
</tr>

@@ -175,22 +215,137 @@ </thead>

<tr>
<td rowspan="3">Merged</td>
<td>Cell 1</td>
<td align="right" rowspan="2">Glycolysis</td>
<td align="right" colspan="2">2 ATP</td>
</tr>
<tr>
<td>Cell 2</td>
<td align="right">2 NADH</td>
<td align="right">3–5 ATP</td>
</tr>
<tr>
<td>Cell 3</td>
<td align="right">Pyruvaye oxidation</td>
<td align="right">2 NADH</td>
<td align="right">5 ATP</td>
</tr>
<tr>
<td align="right" rowspan="3">Citric acid cycle</td>
<td align="right" colspan="2">2 ATP</td>
</tr>
<tr>
<td align="right">6 NADH</td>
<td align="right">15 ATP</td>
</tr>
<tr>
<td align="right">2 FADH2</td>
<td align="right">3 ATP</td>
</tr>
<tr>
<td align="right" colspan="3"><strong>30–32</strong> ATP</td>
</tr>
</tbody>
</table>
And here's how you enable the feature.
### Headerless (optional)
```javascript
var md = require('markdown-it')()
.use(require('markdown-it-multimd-table'), {enableRowspan: true});
Table header can be eliminated.
```markdown
|--|--|--|--|--|--|--|--|
|♜| |♝|♛|♚|♝|♞|♜|
| |♟|♟|♟| |♟|♟|♟|
|♟| |♞| | | | | |
| |♗| | |♟| | | |
| | | | |♙| | | |
| | | | | |♘| | |
|♙|♙|♙|♙| |♙|♙|♙|
|♖|♘|♗|♕|♔| | |♖|
```
If this option is enabled, code above would be parsed as:
<table>
<tbody>
<tr>
<td>♜</td>
<td></td>
<td>♝</td>
<td>♛</td>
<td>♚</td>
<td>♝</td>
<td>♞</td>
<td>♜</td>
</tr>
<tr>
<td></td>
<td>♟</td>
<td>♟</td>
<td>♟</td>
<td></td>
<td>♟</td>
<td>♟</td>
<td>♟</td>
</tr>
<tr>
<td>♟</td>
<td></td>
<td>♞</td>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td>♗</td>
<td></td>
<td></td>
<td>♟</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td>♙</td>
<td></td>
<td></td>
<td></td>
</tr>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
<td>♘</td>
<td></td>
<td></td>
</tr>
<tr>
<td>♙</td>
<td>♙</td>
<td>♙</td>
<td>♙</td>
<td></td>
<td>♙</td>
<td>♙</td>
<td>♙</td>
</tr>
<tr>
<td>♖</td>
<td>♘</td>
<td>♗</td>
<td>♕</td>
<td>♔</td>
<td></td>
<td></td>
<td>♖</td>
</tr>
</tbody>
</table>
## Credits
* [MultiMarkdown](https://fletcher.github.io/MultiMarkdown-6/), Lightweight markup processor to produce HTML, LaTeX, and more.

@@ -197,0 +352,0 @@ * [markdown-it](https://markdown-it.github.io/), Markdown parser, done right. 100% CommonMark support, extensions, syntax plugins & high speed.

'use strict';
var path = require('path');

@@ -7,36 +8,22 @@ var generate = require('markdown-it-testgen');

describe('Basic', function () {
describe('markdown-it-multimd-table-standard', function () {
var md = require('markdown-it')()
.use(require('../'));
generate(path.join(__dirname, 'fixtures/basic.txt'), md);
generate(path.join(__dirname, 'fixtures/standard.txt'), {header: true}, md);
});
describe('Requirements', function () {
describe('markdown-it-multimd-table-unspecified', function () {
var md = require('markdown-it')()
.use(require('../'));
generate(path.join(__dirname, 'fixtures/requirements.txt'), md);
generate(path.join(__dirname, 'fixtures/unspecified.txt'), {header: true}, md);
});
describe('Other Notes', function () {
describe('markdown-it-multimd-table-options', function () {
var md = require('markdown-it')()
.use(require('../'));
generate(path.join(__dirname, 'fixtures/notes.txt'), md);
.use(require('../'), {
multiline: true,
rowspan: true,
headerless: true,
});
generate(path.join(__dirname, 'fixtures/options.txt'), {header: true}, md);
});
describe('Issues', function () {
var md = require('markdown-it')()
.use(require('../'));
generate(path.join(__dirname, 'fixtures/issues.txt'), md);
});
describe('(optional) Multilines', function () {
var md = require('markdown-it')()
.use(require('../'), { enableMultilineRows: true });
generate(path.join(__dirname, 'fixtures/multilines.txt'), md);
});
describe('(optional) Rowspans', function () {
var md = require('markdown-it')()
.use(require('../'), { enableMultilineRows: true, enableRowspan: true });
generate(path.join(__dirname, 'fixtures/rowspan.txt'), md);
});

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc