Refactor routing in App component to enhance navigation and improve error handling by integrating dynamic routes and updating the NotFound route.
This commit is contained in:
55
node_modules/micromark-extension-gfm-table/dev/index.d.ts
generated
vendored
Normal file
55
node_modules/micromark-extension-gfm-table/dev/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
import type {Align} from './lib/infer.js'
|
||||
|
||||
export {gfmTableHtml} from './lib/html.js'
|
||||
export {gfmTable} from './lib/syntax.js'
|
||||
|
||||
/**
|
||||
* Augment types.
|
||||
*/
|
||||
declare module 'micromark-util-types' {
|
||||
/**
|
||||
* State tracked to compile events as HTML,
|
||||
* extended by `micromark-extension-gfm-table`.
|
||||
*/
|
||||
interface CompileData {
|
||||
/**
|
||||
* Alignment of current table.
|
||||
*/
|
||||
tableAlign?: Array<Align> | undefined
|
||||
/**
|
||||
* Current table column.
|
||||
*/
|
||||
tableColumn?: number | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Augment token;
|
||||
* `align` is patched on `table` tokens by
|
||||
* `micromark-extension-gfm-table`.
|
||||
*/
|
||||
interface Token {
|
||||
/**
|
||||
* Alignment of current table.
|
||||
*/
|
||||
_align?: Array<Align> | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of allowed token types,
|
||||
* extended by `micromark-extension-gfm-table`.
|
||||
*/
|
||||
interface TokenTypeMap {
|
||||
tableBody: 'tableBody'
|
||||
tableCellDivider: 'tableCellDivider'
|
||||
tableContent: 'tableContent'
|
||||
tableData: 'tableData'
|
||||
tableDelimiterFiller: 'tableDelimiterFiller'
|
||||
tableDelimiterMarker: 'tableDelimiterMarker'
|
||||
tableDelimiterRow: 'tableDelimiterRow'
|
||||
tableDelimiter: 'tableDelimiter'
|
||||
tableHeader: 'tableHeader'
|
||||
tableHead: 'tableHead'
|
||||
tableRow: 'tableRow'
|
||||
table: 'table'
|
||||
}
|
||||
}
|
2
node_modules/micromark-extension-gfm-table/dev/index.js
generated
vendored
Normal file
2
node_modules/micromark-extension-gfm-table/dev/index.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export {gfmTableHtml} from './lib/html.js'
|
||||
export {gfmTable} from './lib/syntax.js'
|
38
node_modules/micromark-extension-gfm-table/dev/lib/edit-map.d.ts
generated
vendored
Normal file
38
node_modules/micromark-extension-gfm-table/dev/lib/edit-map.d.ts
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @import {Event} from 'micromark-util-types'
|
||||
*/
|
||||
/**
|
||||
* @typedef {[number, number, Array<Event>]} Change
|
||||
* @typedef {[number, number, number]} Jump
|
||||
*/
|
||||
/**
|
||||
* Tracks a bunch of edits.
|
||||
*/
|
||||
export class EditMap {
|
||||
/**
|
||||
* Record of changes.
|
||||
*
|
||||
* @type {Array<Change>}
|
||||
*/
|
||||
map: Array<Change>;
|
||||
/**
|
||||
* Create an edit: a remove and/or add at a certain place.
|
||||
*
|
||||
* @param {number} index
|
||||
* @param {number} remove
|
||||
* @param {Array<Event>} add
|
||||
* @returns {undefined}
|
||||
*/
|
||||
add(index: number, remove: number, add: Array<Event>): undefined;
|
||||
/**
|
||||
* Done, change the events.
|
||||
*
|
||||
* @param {Array<Event>} events
|
||||
* @returns {undefined}
|
||||
*/
|
||||
consume(events: Array<Event>): undefined;
|
||||
}
|
||||
export type Change = [number, number, Array<Event>];
|
||||
export type Jump = [number, number, number];
|
||||
import type { Event } from 'micromark-util-types';
|
||||
//# sourceMappingURL=edit-map.d.ts.map
|
1
node_modules/micromark-extension-gfm-table/dev/lib/edit-map.d.ts.map
generated
vendored
Normal file
1
node_modules/micromark-extension-gfm-table/dev/lib/edit-map.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"edit-map.d.ts","sourceRoot":"","sources":["edit-map.js"],"names":[],"mappings":"AAAA;;GAEG;AAeH;;;GAGG;AAEH;;GAEG;AACH;IAKI;;;;OAIG;IACH,KAFU,KAAK,CAAC,MAAM,CAAC,CAEV;IAGf;;;;;;;OAOG;IACH,WALW,MAAM,UACN,MAAM,OACN,KAAK,CAAC,KAAK,CAAC,GACV,SAAS,CAIrB;IAeD;;;;;OAKG;IACH,gBAHW,KAAK,CAAC,KAAK,CAAC,GACV,SAAS,CA2DrB;CACF;qBA7GY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;mBAC9B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;2BAlBb,sBAAsB"}
|
212
node_modules/micromark-extension-gfm-table/dev/lib/edit-map.js
generated
vendored
Normal file
212
node_modules/micromark-extension-gfm-table/dev/lib/edit-map.js
generated
vendored
Normal file
@@ -0,0 +1,212 @@
|
||||
/**
|
||||
* @import {Event} from 'micromark-util-types'
|
||||
*/
|
||||
|
||||
// Port of `edit_map.rs` from `markdown-rs`.
|
||||
// This should move to `markdown-js` later.
|
||||
|
||||
// Deal with several changes in events, batching them together.
|
||||
//
|
||||
// Preferably, changes should be kept to a minimum.
|
||||
// Sometimes, it’s needed to change the list of events, because parsing can be
|
||||
// messy, and it helps to expose a cleaner interface of events to the compiler
|
||||
// and other users.
|
||||
// It can also help to merge many adjacent similar events.
|
||||
// And, in other cases, it’s needed to parse subcontent: pass some events
|
||||
// through another tokenizer and inject the result.
|
||||
|
||||
/**
|
||||
* @typedef {[number, number, Array<Event>]} Change
|
||||
* @typedef {[number, number, number]} Jump
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tracks a bunch of edits.
|
||||
*/
|
||||
export class EditMap {
|
||||
/**
|
||||
* Create a new edit map.
|
||||
*/
|
||||
constructor() {
|
||||
/**
|
||||
* Record of changes.
|
||||
*
|
||||
* @type {Array<Change>}
|
||||
*/
|
||||
this.map = []
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an edit: a remove and/or add at a certain place.
|
||||
*
|
||||
* @param {number} index
|
||||
* @param {number} remove
|
||||
* @param {Array<Event>} add
|
||||
* @returns {undefined}
|
||||
*/
|
||||
add(index, remove, add) {
|
||||
addImplementation(this, index, remove, add)
|
||||
}
|
||||
|
||||
// To do: add this when moving to `micromark`.
|
||||
// /**
|
||||
// * Create an edit: but insert `add` before existing additions.
|
||||
// *
|
||||
// * @param {number} index
|
||||
// * @param {number} remove
|
||||
// * @param {Array<Event>} add
|
||||
// * @returns {undefined}
|
||||
// */
|
||||
// addBefore(index, remove, add) {
|
||||
// addImplementation(this, index, remove, add, true)
|
||||
// }
|
||||
|
||||
/**
|
||||
* Done, change the events.
|
||||
*
|
||||
* @param {Array<Event>} events
|
||||
* @returns {undefined}
|
||||
*/
|
||||
consume(events) {
|
||||
this.map.sort(function (a, b) {
|
||||
return a[0] - b[0]
|
||||
})
|
||||
|
||||
/* c8 ignore next 3 -- `resolve` is never called without tables, so without edits. */
|
||||
if (this.map.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
// To do: if links are added in events, like they are in `markdown-rs`,
|
||||
// this is needed.
|
||||
// // Calculate jumps: where items in the current list move to.
|
||||
// /** @type {Array<Jump>} */
|
||||
// const jumps = []
|
||||
// let index = 0
|
||||
// let addAcc = 0
|
||||
// let removeAcc = 0
|
||||
// while (index < this.map.length) {
|
||||
// const [at, remove, add] = this.map[index]
|
||||
// removeAcc += remove
|
||||
// addAcc += add.length
|
||||
// jumps.push([at, removeAcc, addAcc])
|
||||
// index += 1
|
||||
// }
|
||||
//
|
||||
// . shiftLinks(events, jumps)
|
||||
|
||||
let index = this.map.length
|
||||
/** @type {Array<Array<Event>>} */
|
||||
const vecs = []
|
||||
while (index > 0) {
|
||||
index -= 1
|
||||
vecs.push(
|
||||
events.slice(this.map[index][0] + this.map[index][1]),
|
||||
this.map[index][2]
|
||||
)
|
||||
|
||||
// Truncate rest.
|
||||
events.length = this.map[index][0]
|
||||
}
|
||||
|
||||
vecs.push(events.slice())
|
||||
events.length = 0
|
||||
|
||||
let slice = vecs.pop()
|
||||
|
||||
while (slice) {
|
||||
for (const element of slice) {
|
||||
events.push(element)
|
||||
}
|
||||
|
||||
slice = vecs.pop()
|
||||
}
|
||||
|
||||
// Truncate everything.
|
||||
this.map.length = 0
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an edit.
|
||||
*
|
||||
* @param {EditMap} editMap
|
||||
* @param {number} at
|
||||
* @param {number} remove
|
||||
* @param {Array<Event>} add
|
||||
* @returns {undefined}
|
||||
*/
|
||||
function addImplementation(editMap, at, remove, add) {
|
||||
let index = 0
|
||||
|
||||
/* c8 ignore next 3 -- `resolve` is never called without tables, so without edits. */
|
||||
if (remove === 0 && add.length === 0) {
|
||||
return
|
||||
}
|
||||
|
||||
while (index < editMap.map.length) {
|
||||
if (editMap.map[index][0] === at) {
|
||||
editMap.map[index][1] += remove
|
||||
|
||||
// To do: before not used by tables, use when moving to micromark.
|
||||
// if (before) {
|
||||
// add.push(...editMap.map[index][2])
|
||||
// editMap.map[index][2] = add
|
||||
// } else {
|
||||
editMap.map[index][2].push(...add)
|
||||
// }
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
index += 1
|
||||
}
|
||||
|
||||
editMap.map.push([at, remove, add])
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Shift `previous` and `next` links according to `jumps`.
|
||||
// *
|
||||
// * This fixes links in case there are events removed or added between them.
|
||||
// *
|
||||
// * @param {Array<Event>} events
|
||||
// * @param {Array<Jump>} jumps
|
||||
// */
|
||||
// function shiftLinks(events, jumps) {
|
||||
// let jumpIndex = 0
|
||||
// let index = 0
|
||||
// let add = 0
|
||||
// let rm = 0
|
||||
|
||||
// while (index < events.length) {
|
||||
// const rmCurr = rm
|
||||
|
||||
// while (jumpIndex < jumps.length && jumps[jumpIndex][0] <= index) {
|
||||
// add = jumps[jumpIndex][2]
|
||||
// rm = jumps[jumpIndex][1]
|
||||
// jumpIndex += 1
|
||||
// }
|
||||
|
||||
// // Ignore items that will be removed.
|
||||
// if (rm > rmCurr) {
|
||||
// index += rm - rmCurr
|
||||
// } else {
|
||||
// // ?
|
||||
// // if let Some(link) = &events[index].link {
|
||||
// // if let Some(next) = link.next {
|
||||
// // events[next].link.as_mut().unwrap().previous = Some(index + add - rm);
|
||||
// // while jumpIndex < jumps.len() && jumps[jumpIndex].0 <= next {
|
||||
// // add = jumps[jumpIndex].2;
|
||||
// // rm = jumps[jumpIndex].1;
|
||||
// // jumpIndex += 1;
|
||||
// // }
|
||||
// // events[index].link.as_mut().unwrap().next = Some(next + add - rm);
|
||||
// // index = next;
|
||||
// // continue;
|
||||
// // }
|
||||
// // }
|
||||
// index += 1
|
||||
// }
|
||||
// }
|
||||
// }
|
11
node_modules/micromark-extension-gfm-table/dev/lib/html.d.ts
generated
vendored
Normal file
11
node_modules/micromark-extension-gfm-table/dev/lib/html.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Create an HTML extension for `micromark` to support GitHub tables when
|
||||
* serializing to HTML.
|
||||
*
|
||||
* @returns {HtmlExtension}
|
||||
* Extension for `micromark` that can be passed in `htmlExtensions` to
|
||||
* support GitHub tables when serializing to HTML.
|
||||
*/
|
||||
export function gfmTableHtml(): HtmlExtension;
|
||||
import type { HtmlExtension } from 'micromark-util-types';
|
||||
//# sourceMappingURL=html.d.ts.map
|
1
node_modules/micromark-extension-gfm-table/dev/lib/html.d.ts.map
generated
vendored
Normal file
1
node_modules/micromark-extension-gfm-table/dev/lib/html.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["html.js"],"names":[],"mappings":"AAeA;;;;;;;GAOG;AACH,gCAJa,aAAa,CAsHzB;mCAxI+B,sBAAsB"}
|
148
node_modules/micromark-extension-gfm-table/dev/lib/html.js
generated
vendored
Normal file
148
node_modules/micromark-extension-gfm-table/dev/lib/html.js
generated
vendored
Normal file
@@ -0,0 +1,148 @@
|
||||
/**
|
||||
* @import {HtmlExtension} from 'micromark-util-types'
|
||||
*/
|
||||
|
||||
import {ok as assert} from 'devlop'
|
||||
|
||||
const alignment = {
|
||||
none: '',
|
||||
left: ' align="left"',
|
||||
right: ' align="right"',
|
||||
center: ' align="center"'
|
||||
}
|
||||
|
||||
// To do: micromark@5: use `infer` here, when all events are exposed.
|
||||
|
||||
/**
|
||||
* Create an HTML extension for `micromark` to support GitHub tables when
|
||||
* serializing to HTML.
|
||||
*
|
||||
* @returns {HtmlExtension}
|
||||
* Extension for `micromark` that can be passed in `htmlExtensions` to
|
||||
* support GitHub tables when serializing to HTML.
|
||||
*/
|
||||
export function gfmTableHtml() {
|
||||
return {
|
||||
enter: {
|
||||
table(token) {
|
||||
const tableAlign = token._align
|
||||
assert(tableAlign, 'expected `_align`')
|
||||
this.lineEndingIfNeeded()
|
||||
this.tag('<table>')
|
||||
this.setData('tableAlign', tableAlign)
|
||||
},
|
||||
tableBody() {
|
||||
this.tag('<tbody>')
|
||||
},
|
||||
tableData() {
|
||||
const tableAlign = this.getData('tableAlign')
|
||||
const tableColumn = this.getData('tableColumn')
|
||||
assert(tableAlign, 'expected `tableAlign`')
|
||||
assert(typeof tableColumn === 'number', 'expected `tableColumn`')
|
||||
const align = alignment[tableAlign[tableColumn]]
|
||||
|
||||
if (align === undefined) {
|
||||
// Capture results to ignore them.
|
||||
this.buffer()
|
||||
} else {
|
||||
this.lineEndingIfNeeded()
|
||||
this.tag('<td' + align + '>')
|
||||
}
|
||||
},
|
||||
tableHead() {
|
||||
this.lineEndingIfNeeded()
|
||||
this.tag('<thead>')
|
||||
},
|
||||
tableHeader() {
|
||||
const tableAlign = this.getData('tableAlign')
|
||||
const tableColumn = this.getData('tableColumn')
|
||||
assert(tableAlign, 'expected `tableAlign`')
|
||||
assert(typeof tableColumn === 'number', 'expected `tableColumn`')
|
||||
const align = alignment[tableAlign[tableColumn]]
|
||||
this.lineEndingIfNeeded()
|
||||
this.tag('<th' + align + '>')
|
||||
},
|
||||
tableRow() {
|
||||
this.setData('tableColumn', 0)
|
||||
this.lineEndingIfNeeded()
|
||||
this.tag('<tr>')
|
||||
}
|
||||
},
|
||||
exit: {
|
||||
// Overwrite the default code text data handler to unescape escaped pipes when
|
||||
// they are in tables.
|
||||
codeTextData(token) {
|
||||
let value = this.sliceSerialize(token)
|
||||
|
||||
if (this.getData('tableAlign')) {
|
||||
value = value.replace(/\\([\\|])/g, replace)
|
||||
}
|
||||
|
||||
this.raw(this.encode(value))
|
||||
},
|
||||
table() {
|
||||
this.setData('tableAlign')
|
||||
// Note: we don’t set `slurpAllLineEndings` anymore, in delimiter rows,
|
||||
// but we do need to reset it to match a funky newline GH generates for
|
||||
// list items combined with tables.
|
||||
this.setData('slurpAllLineEndings')
|
||||
this.lineEndingIfNeeded()
|
||||
this.tag('</table>')
|
||||
},
|
||||
tableBody() {
|
||||
this.lineEndingIfNeeded()
|
||||
this.tag('</tbody>')
|
||||
},
|
||||
tableData() {
|
||||
const tableAlign = this.getData('tableAlign')
|
||||
const tableColumn = this.getData('tableColumn')
|
||||
assert(tableAlign, 'expected `tableAlign`')
|
||||
assert(typeof tableColumn === 'number', 'expected `tableColumn`')
|
||||
|
||||
if (tableColumn in tableAlign) {
|
||||
this.tag('</td>')
|
||||
this.setData('tableColumn', tableColumn + 1)
|
||||
} else {
|
||||
// Stop capturing.
|
||||
this.resume()
|
||||
}
|
||||
},
|
||||
tableHead() {
|
||||
this.lineEndingIfNeeded()
|
||||
this.tag('</thead>')
|
||||
},
|
||||
tableHeader() {
|
||||
const tableColumn = this.getData('tableColumn')
|
||||
assert(typeof tableColumn === 'number', 'expected `tableColumn`')
|
||||
this.tag('</th>')
|
||||
this.setData('tableColumn', tableColumn + 1)
|
||||
},
|
||||
tableRow() {
|
||||
const tableAlign = this.getData('tableAlign')
|
||||
let tableColumn = this.getData('tableColumn')
|
||||
assert(tableAlign, 'expected `tableAlign`')
|
||||
assert(typeof tableColumn === 'number', 'expected `tableColumn`')
|
||||
|
||||
while (tableColumn < tableAlign.length) {
|
||||
this.lineEndingIfNeeded()
|
||||
this.tag('<td' + alignment[tableAlign[tableColumn]] + '></td>')
|
||||
tableColumn++
|
||||
}
|
||||
|
||||
this.setData('tableColumn', tableColumn)
|
||||
this.lineEndingIfNeeded()
|
||||
this.tag('</tr>')
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} $0
|
||||
* @param {string} $1
|
||||
* @returns {string}
|
||||
*/
|
||||
function replace($0, $1) {
|
||||
// Pipes work, backslashes don’t (but can’t escape pipes).
|
||||
return $1 === '|' ? $1 : $0
|
||||
}
|
14
node_modules/micromark-extension-gfm-table/dev/lib/infer.d.ts
generated
vendored
Normal file
14
node_modules/micromark-extension-gfm-table/dev/lib/infer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Figure out the alignment of a GFM table.
|
||||
*
|
||||
* @param {Readonly<Array<Event>>} events
|
||||
* List of events.
|
||||
* @param {number} index
|
||||
* Table enter event.
|
||||
* @returns {Array<Align>}
|
||||
* List of aligns.
|
||||
*/
|
||||
export function gfmTableAlign(events: Readonly<Array<Event>>, index: number): Array<Align>;
|
||||
export type Align = "center" | "left" | "none" | "right";
|
||||
import type { Event } from 'micromark-util-types';
|
||||
//# sourceMappingURL=infer.d.ts.map
|
1
node_modules/micromark-extension-gfm-table/dev/lib/infer.d.ts.map
generated
vendored
Normal file
1
node_modules/micromark-extension-gfm-table/dev/lib/infer.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"infer.d.ts","sourceRoot":"","sources":["infer.js"],"names":[],"mappings":"AAUA;;;;;;;;;GASG;AACH,sCAPW,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAEtB,MAAM,GAEJ,KAAK,CAAC,KAAK,CAAC,CA8CxB;oBA1DY,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO;2BAJzB,sBAAsB"}
|
64
node_modules/micromark-extension-gfm-table/dev/lib/infer.js
generated
vendored
Normal file
64
node_modules/micromark-extension-gfm-table/dev/lib/infer.js
generated
vendored
Normal file
@@ -0,0 +1,64 @@
|
||||
/**
|
||||
* @import {Event} from 'micromark-util-types'
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {'center' | 'left' | 'none' | 'right'} Align
|
||||
*/
|
||||
|
||||
import {ok as assert} from 'devlop'
|
||||
|
||||
/**
|
||||
* Figure out the alignment of a GFM table.
|
||||
*
|
||||
* @param {Readonly<Array<Event>>} events
|
||||
* List of events.
|
||||
* @param {number} index
|
||||
* Table enter event.
|
||||
* @returns {Array<Align>}
|
||||
* List of aligns.
|
||||
*/
|
||||
export function gfmTableAlign(events, index) {
|
||||
assert(events[index][1].type === 'table', 'expected table')
|
||||
let inDelimiterRow = false
|
||||
/** @type {Array<Align>} */
|
||||
const align = []
|
||||
|
||||
while (index < events.length) {
|
||||
const event = events[index]
|
||||
|
||||
if (inDelimiterRow) {
|
||||
if (event[0] === 'enter') {
|
||||
// Start of alignment value: set a new column.
|
||||
// To do: `markdown-rs` uses `tableDelimiterCellValue`.
|
||||
if (event[1].type === 'tableContent') {
|
||||
align.push(
|
||||
events[index + 1][1].type === 'tableDelimiterMarker'
|
||||
? 'left'
|
||||
: 'none'
|
||||
)
|
||||
}
|
||||
}
|
||||
// Exits:
|
||||
// End of alignment value: change the column.
|
||||
// To do: `markdown-rs` uses `tableDelimiterCellValue`.
|
||||
else if (event[1].type === 'tableContent') {
|
||||
if (events[index - 1][1].type === 'tableDelimiterMarker') {
|
||||
const alignIndex = align.length - 1
|
||||
|
||||
align[alignIndex] = align[alignIndex] === 'left' ? 'center' : 'right'
|
||||
}
|
||||
}
|
||||
// Done!
|
||||
else if (event[1].type === 'tableDelimiterRow') {
|
||||
break
|
||||
}
|
||||
} else if (event[0] === 'enter' && event[1].type === 'tableDelimiterRow') {
|
||||
inDelimiterRow = true
|
||||
}
|
||||
|
||||
index += 1
|
||||
}
|
||||
|
||||
return align
|
||||
}
|
18
node_modules/micromark-extension-gfm-table/dev/lib/syntax.d.ts
generated
vendored
Normal file
18
node_modules/micromark-extension-gfm-table/dev/lib/syntax.d.ts
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Create an HTML extension for `micromark` to support GitHub tables syntax.
|
||||
*
|
||||
* @returns {Extension}
|
||||
* Extension for `micromark` that can be passed in `extensions` to enable GFM
|
||||
* table syntax.
|
||||
*/
|
||||
export function gfmTable(): Extension;
|
||||
/**
|
||||
* Cell info.
|
||||
*/
|
||||
export type Range = [number, number, number, number];
|
||||
/**
|
||||
* Where we are: `1` for head row, `2` for delimiter row, `3` for body row.
|
||||
*/
|
||||
export type RowKind = 0 | 1 | 2 | 3;
|
||||
import type { Extension } from 'micromark-util-types';
|
||||
//# sourceMappingURL=syntax.d.ts.map
|
1
node_modules/micromark-extension-gfm-table/dev/lib/syntax.d.ts.map
generated
vendored
Normal file
1
node_modules/micromark-extension-gfm-table/dev/lib/syntax.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"syntax.d.ts","sourceRoot":"","sources":["syntax.js"],"names":[],"mappings":"AAuBA;;;;;;GAMG;AACH,4BAJa,SAAS,CAUrB;;;;oBA/BY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;;;;sBAGhC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;+BAPoE,sBAAsB"}
|
941
node_modules/micromark-extension-gfm-table/dev/lib/syntax.js
generated
vendored
Normal file
941
node_modules/micromark-extension-gfm-table/dev/lib/syntax.js
generated
vendored
Normal file
@@ -0,0 +1,941 @@
|
||||
/**
|
||||
* @import {Event, Extension, Point, Resolver, State, Token, TokenizeContext, Tokenizer} from 'micromark-util-types'
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {[number, number, number, number]} Range
|
||||
* Cell info.
|
||||
*
|
||||
* @typedef {0 | 1 | 2 | 3} RowKind
|
||||
* Where we are: `1` for head row, `2` for delimiter row, `3` for body row.
|
||||
*/
|
||||
|
||||
import {ok as assert} from 'devlop'
|
||||
import {factorySpace} from 'micromark-factory-space'
|
||||
import {
|
||||
markdownLineEnding,
|
||||
markdownLineEndingOrSpace,
|
||||
markdownSpace
|
||||
} from 'micromark-util-character'
|
||||
import {codes, constants, types} from 'micromark-util-symbol'
|
||||
import {EditMap} from './edit-map.js'
|
||||
import {gfmTableAlign} from './infer.js'
|
||||
|
||||
/**
|
||||
* Create an HTML extension for `micromark` to support GitHub tables syntax.
|
||||
*
|
||||
* @returns {Extension}
|
||||
* Extension for `micromark` that can be passed in `extensions` to enable GFM
|
||||
* table syntax.
|
||||
*/
|
||||
export function gfmTable() {
|
||||
return {
|
||||
flow: {
|
||||
null: {name: 'table', tokenize: tokenizeTable, resolveAll: resolveTable}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @this {TokenizeContext}
|
||||
* @type {Tokenizer}
|
||||
*/
|
||||
function tokenizeTable(effects, ok, nok) {
|
||||
const self = this
|
||||
let size = 0
|
||||
let sizeB = 0
|
||||
/** @type {boolean | undefined} */
|
||||
let seen
|
||||
|
||||
return start
|
||||
|
||||
/**
|
||||
* Start of a GFM table.
|
||||
*
|
||||
* If there is a valid table row or table head before, then we try to parse
|
||||
* another row.
|
||||
* Otherwise, we try to parse a head.
|
||||
*
|
||||
* ```markdown
|
||||
* > | | a |
|
||||
* ^
|
||||
* | | - |
|
||||
* > | | b |
|
||||
* ^
|
||||
* ```
|
||||
* @type {State}
|
||||
*/
|
||||
function start(code) {
|
||||
let index = self.events.length - 1
|
||||
|
||||
while (index > -1) {
|
||||
const type = self.events[index][1].type
|
||||
if (
|
||||
type === types.lineEnding ||
|
||||
// Note: markdown-rs uses `whitespace` instead of `linePrefix`
|
||||
type === types.linePrefix
|
||||
)
|
||||
index--
|
||||
else break
|
||||
}
|
||||
|
||||
const tail = index > -1 ? self.events[index][1].type : null
|
||||
|
||||
const next =
|
||||
tail === 'tableHead' || tail === 'tableRow' ? bodyRowStart : headRowBefore
|
||||
|
||||
// Don’t allow lazy body rows.
|
||||
if (next === bodyRowStart && self.parser.lazy[self.now().line]) {
|
||||
return nok(code)
|
||||
}
|
||||
|
||||
return next(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* Before table head row.
|
||||
*
|
||||
* ```markdown
|
||||
* > | | a |
|
||||
* ^
|
||||
* | | - |
|
||||
* | | b |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headRowBefore(code) {
|
||||
effects.enter('tableHead')
|
||||
effects.enter('tableRow')
|
||||
return headRowStart(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* Before table head row, after whitespace.
|
||||
*
|
||||
* ```markdown
|
||||
* > | | a |
|
||||
* ^
|
||||
* | | - |
|
||||
* | | b |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headRowStart(code) {
|
||||
if (code === codes.verticalBar) {
|
||||
return headRowBreak(code)
|
||||
}
|
||||
|
||||
// To do: micromark-js should let us parse our own whitespace in extensions,
|
||||
// like `markdown-rs`:
|
||||
//
|
||||
// ```js
|
||||
// // 4+ spaces.
|
||||
// if (markdownSpace(code)) {
|
||||
// return nok(code)
|
||||
// }
|
||||
// ```
|
||||
|
||||
seen = true
|
||||
// Count the first character, that isn’t a pipe, double.
|
||||
sizeB += 1
|
||||
return headRowBreak(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* At break in table head row.
|
||||
*
|
||||
* ```markdown
|
||||
* > | | a |
|
||||
* ^
|
||||
* ^
|
||||
* ^
|
||||
* | | - |
|
||||
* | | b |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headRowBreak(code) {
|
||||
if (code === codes.eof) {
|
||||
// Note: in `markdown-rs`, we need to reset, in `micromark-js` we don‘t.
|
||||
return nok(code)
|
||||
}
|
||||
|
||||
if (markdownLineEnding(code)) {
|
||||
// If anything other than one pipe (ignoring whitespace) was used, it’s fine.
|
||||
if (sizeB > 1) {
|
||||
sizeB = 0
|
||||
// To do: check if this works.
|
||||
// Feel free to interrupt:
|
||||
self.interrupt = true
|
||||
effects.exit('tableRow')
|
||||
effects.enter(types.lineEnding)
|
||||
effects.consume(code)
|
||||
effects.exit(types.lineEnding)
|
||||
return headDelimiterStart
|
||||
}
|
||||
|
||||
// Note: in `markdown-rs`, we need to reset, in `micromark-js` we don‘t.
|
||||
return nok(code)
|
||||
}
|
||||
|
||||
if (markdownSpace(code)) {
|
||||
// To do: check if this is fine.
|
||||
// effects.attempt(State::Next(StateName::GfmTableHeadRowBreak), State::Nok)
|
||||
// State::Retry(space_or_tab(tokenizer))
|
||||
return factorySpace(effects, headRowBreak, types.whitespace)(code)
|
||||
}
|
||||
|
||||
sizeB += 1
|
||||
|
||||
if (seen) {
|
||||
seen = false
|
||||
// Header cell count.
|
||||
size += 1
|
||||
}
|
||||
|
||||
if (code === codes.verticalBar) {
|
||||
effects.enter('tableCellDivider')
|
||||
effects.consume(code)
|
||||
effects.exit('tableCellDivider')
|
||||
// Whether a delimiter was seen.
|
||||
seen = true
|
||||
return headRowBreak
|
||||
}
|
||||
|
||||
// Anything else is cell data.
|
||||
effects.enter(types.data)
|
||||
return headRowData(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* In table head row data.
|
||||
*
|
||||
* ```markdown
|
||||
* > | | a |
|
||||
* ^
|
||||
* | | - |
|
||||
* | | b |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headRowData(code) {
|
||||
if (
|
||||
code === codes.eof ||
|
||||
code === codes.verticalBar ||
|
||||
markdownLineEndingOrSpace(code)
|
||||
) {
|
||||
effects.exit(types.data)
|
||||
return headRowBreak(code)
|
||||
}
|
||||
|
||||
effects.consume(code)
|
||||
return code === codes.backslash ? headRowEscape : headRowData
|
||||
}
|
||||
|
||||
/**
|
||||
* In table head row escape.
|
||||
*
|
||||
* ```markdown
|
||||
* > | | a\-b |
|
||||
* ^
|
||||
* | | ---- |
|
||||
* | | c |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headRowEscape(code) {
|
||||
if (code === codes.backslash || code === codes.verticalBar) {
|
||||
effects.consume(code)
|
||||
return headRowData
|
||||
}
|
||||
|
||||
return headRowData(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* Before delimiter row.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | - |
|
||||
* ^
|
||||
* | | b |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterStart(code) {
|
||||
// Reset `interrupt`.
|
||||
self.interrupt = false
|
||||
|
||||
// Note: in `markdown-rs`, we need to handle piercing here too.
|
||||
if (self.parser.lazy[self.now().line]) {
|
||||
return nok(code)
|
||||
}
|
||||
|
||||
effects.enter('tableDelimiterRow')
|
||||
// Track if we’ve seen a `:` or `|`.
|
||||
seen = false
|
||||
|
||||
if (markdownSpace(code)) {
|
||||
assert(self.parser.constructs.disable.null, 'expected `disabled.null`')
|
||||
return factorySpace(
|
||||
effects,
|
||||
headDelimiterBefore,
|
||||
types.linePrefix,
|
||||
self.parser.constructs.disable.null.includes('codeIndented')
|
||||
? undefined
|
||||
: constants.tabSize
|
||||
)(code)
|
||||
}
|
||||
|
||||
return headDelimiterBefore(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* Before delimiter row, after optional whitespace.
|
||||
*
|
||||
* Reused when a `|` is found later, to parse another cell.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | - |
|
||||
* ^
|
||||
* | | b |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterBefore(code) {
|
||||
if (code === codes.dash || code === codes.colon) {
|
||||
return headDelimiterValueBefore(code)
|
||||
}
|
||||
|
||||
if (code === codes.verticalBar) {
|
||||
seen = true
|
||||
// If we start with a pipe, we open a cell marker.
|
||||
effects.enter('tableCellDivider')
|
||||
effects.consume(code)
|
||||
effects.exit('tableCellDivider')
|
||||
return headDelimiterCellBefore
|
||||
}
|
||||
|
||||
// More whitespace / empty row not allowed at start.
|
||||
return headDelimiterNok(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* After `|`, before delimiter cell.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | - |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterCellBefore(code) {
|
||||
if (markdownSpace(code)) {
|
||||
return factorySpace(
|
||||
effects,
|
||||
headDelimiterValueBefore,
|
||||
types.whitespace
|
||||
)(code)
|
||||
}
|
||||
|
||||
return headDelimiterValueBefore(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* Before delimiter cell value.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | - |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterValueBefore(code) {
|
||||
// Align: left.
|
||||
if (code === codes.colon) {
|
||||
sizeB += 1
|
||||
seen = true
|
||||
|
||||
effects.enter('tableDelimiterMarker')
|
||||
effects.consume(code)
|
||||
effects.exit('tableDelimiterMarker')
|
||||
return headDelimiterLeftAlignmentAfter
|
||||
}
|
||||
|
||||
// Align: none.
|
||||
if (code === codes.dash) {
|
||||
sizeB += 1
|
||||
// To do: seems weird that this *isn’t* left aligned, but that state is used?
|
||||
return headDelimiterLeftAlignmentAfter(code)
|
||||
}
|
||||
|
||||
if (code === codes.eof || markdownLineEnding(code)) {
|
||||
return headDelimiterCellAfter(code)
|
||||
}
|
||||
|
||||
return headDelimiterNok(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* After delimiter cell left alignment marker.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | :- |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterLeftAlignmentAfter(code) {
|
||||
if (code === codes.dash) {
|
||||
effects.enter('tableDelimiterFiller')
|
||||
return headDelimiterFiller(code)
|
||||
}
|
||||
|
||||
// Anything else is not ok after the left-align colon.
|
||||
return headDelimiterNok(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* In delimiter cell filler.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | - |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterFiller(code) {
|
||||
if (code === codes.dash) {
|
||||
effects.consume(code)
|
||||
return headDelimiterFiller
|
||||
}
|
||||
|
||||
// Align is `center` if it was `left`, `right` otherwise.
|
||||
if (code === codes.colon) {
|
||||
seen = true
|
||||
effects.exit('tableDelimiterFiller')
|
||||
effects.enter('tableDelimiterMarker')
|
||||
effects.consume(code)
|
||||
effects.exit('tableDelimiterMarker')
|
||||
return headDelimiterRightAlignmentAfter
|
||||
}
|
||||
|
||||
effects.exit('tableDelimiterFiller')
|
||||
return headDelimiterRightAlignmentAfter(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* After delimiter cell right alignment marker.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | -: |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterRightAlignmentAfter(code) {
|
||||
if (markdownSpace(code)) {
|
||||
return factorySpace(
|
||||
effects,
|
||||
headDelimiterCellAfter,
|
||||
types.whitespace
|
||||
)(code)
|
||||
}
|
||||
|
||||
return headDelimiterCellAfter(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* After delimiter cell.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | -: |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterCellAfter(code) {
|
||||
if (code === codes.verticalBar) {
|
||||
return headDelimiterBefore(code)
|
||||
}
|
||||
|
||||
if (code === codes.eof || markdownLineEnding(code)) {
|
||||
// Exit when:
|
||||
// * there was no `:` or `|` at all (it’s a thematic break or setext
|
||||
// underline instead)
|
||||
// * the header cell count is not the delimiter cell count
|
||||
if (!seen || size !== sizeB) {
|
||||
return headDelimiterNok(code)
|
||||
}
|
||||
|
||||
// Note: in markdown-rs`, a reset is needed here.
|
||||
effects.exit('tableDelimiterRow')
|
||||
effects.exit('tableHead')
|
||||
// To do: in `markdown-rs`, resolvers need to be registered manually.
|
||||
// effects.register_resolver(ResolveName::GfmTable)
|
||||
return ok(code)
|
||||
}
|
||||
|
||||
return headDelimiterNok(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* In delimiter row, at a disallowed byte.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | x |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterNok(code) {
|
||||
// Note: in `markdown-rs`, we need to reset, in `micromark-js` we don‘t.
|
||||
return nok(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* Before table body row.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* | | - |
|
||||
* > | | b |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function bodyRowStart(code) {
|
||||
// Note: in `markdown-rs` we need to manually take care of a prefix,
|
||||
// but in `micromark-js` that is done for us, so if we’re here, we’re
|
||||
// never at whitespace.
|
||||
effects.enter('tableRow')
|
||||
return bodyRowBreak(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* At break in table body row.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* | | - |
|
||||
* > | | b |
|
||||
* ^
|
||||
* ^
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function bodyRowBreak(code) {
|
||||
if (code === codes.verticalBar) {
|
||||
effects.enter('tableCellDivider')
|
||||
effects.consume(code)
|
||||
effects.exit('tableCellDivider')
|
||||
return bodyRowBreak
|
||||
}
|
||||
|
||||
if (code === codes.eof || markdownLineEnding(code)) {
|
||||
effects.exit('tableRow')
|
||||
return ok(code)
|
||||
}
|
||||
|
||||
if (markdownSpace(code)) {
|
||||
return factorySpace(effects, bodyRowBreak, types.whitespace)(code)
|
||||
}
|
||||
|
||||
// Anything else is cell content.
|
||||
effects.enter(types.data)
|
||||
return bodyRowData(code)
|
||||
}
|
||||
|
||||
/**
|
||||
* In table body row data.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* | | - |
|
||||
* > | | b |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function bodyRowData(code) {
|
||||
if (
|
||||
code === codes.eof ||
|
||||
code === codes.verticalBar ||
|
||||
markdownLineEndingOrSpace(code)
|
||||
) {
|
||||
effects.exit(types.data)
|
||||
return bodyRowBreak(code)
|
||||
}
|
||||
|
||||
effects.consume(code)
|
||||
return code === codes.backslash ? bodyRowEscape : bodyRowData
|
||||
}
|
||||
|
||||
/**
|
||||
* In table body row escape.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* | | ---- |
|
||||
* > | | b\-c |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function bodyRowEscape(code) {
|
||||
if (code === codes.backslash || code === codes.verticalBar) {
|
||||
effects.consume(code)
|
||||
return bodyRowData
|
||||
}
|
||||
|
||||
return bodyRowData(code)
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {Resolver} */
|
||||
|
||||
function resolveTable(events, context) {
|
||||
let index = -1
|
||||
let inFirstCellAwaitingPipe = true
|
||||
/** @type {RowKind} */
|
||||
let rowKind = 0
|
||||
/** @type {Range} */
|
||||
let lastCell = [0, 0, 0, 0]
|
||||
/** @type {Range} */
|
||||
let cell = [0, 0, 0, 0]
|
||||
let afterHeadAwaitingFirstBodyRow = false
|
||||
let lastTableEnd = 0
|
||||
/** @type {Token | undefined} */
|
||||
let currentTable
|
||||
/** @type {Token | undefined} */
|
||||
let currentBody
|
||||
/** @type {Token | undefined} */
|
||||
let currentCell
|
||||
|
||||
const map = new EditMap()
|
||||
|
||||
while (++index < events.length) {
|
||||
const event = events[index]
|
||||
const token = event[1]
|
||||
|
||||
if (event[0] === 'enter') {
|
||||
// Start of head.
|
||||
if (token.type === 'tableHead') {
|
||||
afterHeadAwaitingFirstBodyRow = false
|
||||
|
||||
// Inject previous (body end and) table end.
|
||||
if (lastTableEnd !== 0) {
|
||||
assert(currentTable, 'there should be a table opening')
|
||||
flushTableEnd(map, context, lastTableEnd, currentTable, currentBody)
|
||||
currentBody = undefined
|
||||
lastTableEnd = 0
|
||||
}
|
||||
|
||||
// Inject table start.
|
||||
currentTable = {
|
||||
type: 'table',
|
||||
start: Object.assign({}, token.start),
|
||||
// Note: correct end is set later.
|
||||
end: Object.assign({}, token.end)
|
||||
}
|
||||
map.add(index, 0, [['enter', currentTable, context]])
|
||||
} else if (
|
||||
token.type === 'tableRow' ||
|
||||
token.type === 'tableDelimiterRow'
|
||||
) {
|
||||
inFirstCellAwaitingPipe = true
|
||||
currentCell = undefined
|
||||
lastCell = [0, 0, 0, 0]
|
||||
cell = [0, index + 1, 0, 0]
|
||||
|
||||
// Inject table body start.
|
||||
if (afterHeadAwaitingFirstBodyRow) {
|
||||
afterHeadAwaitingFirstBodyRow = false
|
||||
currentBody = {
|
||||
type: 'tableBody',
|
||||
start: Object.assign({}, token.start),
|
||||
// Note: correct end is set later.
|
||||
end: Object.assign({}, token.end)
|
||||
}
|
||||
map.add(index, 0, [['enter', currentBody, context]])
|
||||
}
|
||||
|
||||
rowKind = token.type === 'tableDelimiterRow' ? 2 : currentBody ? 3 : 1
|
||||
}
|
||||
// Cell data.
|
||||
else if (
|
||||
rowKind &&
|
||||
(token.type === types.data ||
|
||||
token.type === 'tableDelimiterMarker' ||
|
||||
token.type === 'tableDelimiterFiller')
|
||||
) {
|
||||
inFirstCellAwaitingPipe = false
|
||||
|
||||
// First value in cell.
|
||||
if (cell[2] === 0) {
|
||||
if (lastCell[1] !== 0) {
|
||||
cell[0] = cell[1]
|
||||
currentCell = flushCell(
|
||||
map,
|
||||
context,
|
||||
lastCell,
|
||||
rowKind,
|
||||
undefined,
|
||||
currentCell
|
||||
)
|
||||
lastCell = [0, 0, 0, 0]
|
||||
}
|
||||
|
||||
cell[2] = index
|
||||
}
|
||||
} else if (token.type === 'tableCellDivider') {
|
||||
if (inFirstCellAwaitingPipe) {
|
||||
inFirstCellAwaitingPipe = false
|
||||
} else {
|
||||
if (lastCell[1] !== 0) {
|
||||
cell[0] = cell[1]
|
||||
currentCell = flushCell(
|
||||
map,
|
||||
context,
|
||||
lastCell,
|
||||
rowKind,
|
||||
undefined,
|
||||
currentCell
|
||||
)
|
||||
}
|
||||
|
||||
lastCell = cell
|
||||
cell = [lastCell[1], index, 0, 0]
|
||||
}
|
||||
}
|
||||
}
|
||||
// Exit events.
|
||||
else if (token.type === 'tableHead') {
|
||||
afterHeadAwaitingFirstBodyRow = true
|
||||
lastTableEnd = index
|
||||
} else if (
|
||||
token.type === 'tableRow' ||
|
||||
token.type === 'tableDelimiterRow'
|
||||
) {
|
||||
lastTableEnd = index
|
||||
|
||||
if (lastCell[1] !== 0) {
|
||||
cell[0] = cell[1]
|
||||
currentCell = flushCell(
|
||||
map,
|
||||
context,
|
||||
lastCell,
|
||||
rowKind,
|
||||
index,
|
||||
currentCell
|
||||
)
|
||||
} else if (cell[1] !== 0) {
|
||||
currentCell = flushCell(map, context, cell, rowKind, index, currentCell)
|
||||
}
|
||||
|
||||
rowKind = 0
|
||||
} else if (
|
||||
rowKind &&
|
||||
(token.type === types.data ||
|
||||
token.type === 'tableDelimiterMarker' ||
|
||||
token.type === 'tableDelimiterFiller')
|
||||
) {
|
||||
cell[3] = index
|
||||
}
|
||||
}
|
||||
|
||||
if (lastTableEnd !== 0) {
|
||||
assert(currentTable, 'expected table opening')
|
||||
flushTableEnd(map, context, lastTableEnd, currentTable, currentBody)
|
||||
}
|
||||
|
||||
map.consume(context.events)
|
||||
|
||||
// To do: move this into `html`, when events are exposed there.
|
||||
// That’s what `markdown-rs` does.
|
||||
// That needs updates to `mdast-util-gfm-table`.
|
||||
index = -1
|
||||
while (++index < context.events.length) {
|
||||
const event = context.events[index]
|
||||
if (event[0] === 'enter' && event[1].type === 'table') {
|
||||
event[1]._align = gfmTableAlign(context.events, index)
|
||||
}
|
||||
}
|
||||
|
||||
return events
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a cell.
|
||||
*
|
||||
* @param {EditMap} map
|
||||
* @param {Readonly<TokenizeContext>} context
|
||||
* @param {Readonly<Range>} range
|
||||
* @param {RowKind} rowKind
|
||||
* @param {number | undefined} rowEnd
|
||||
* @param {Token | undefined} previousCell
|
||||
* @returns {Token | undefined}
|
||||
*/
|
||||
// eslint-disable-next-line max-params
|
||||
function flushCell(map, context, range, rowKind, rowEnd, previousCell) {
|
||||
// `markdown-rs` uses:
|
||||
// rowKind === 2 ? 'tableDelimiterCell' : 'tableCell'
|
||||
const groupName =
|
||||
rowKind === 1
|
||||
? 'tableHeader'
|
||||
: rowKind === 2
|
||||
? 'tableDelimiter'
|
||||
: 'tableData'
|
||||
// `markdown-rs` uses:
|
||||
// rowKind === 2 ? 'tableDelimiterCellValue' : 'tableCellText'
|
||||
const valueName = 'tableContent'
|
||||
|
||||
// Insert an exit for the previous cell, if there is one.
|
||||
//
|
||||
// ```markdown
|
||||
// > | | aa | bb | cc |
|
||||
// ^-- exit
|
||||
// ^^^^-- this cell
|
||||
// ```
|
||||
if (range[0] !== 0) {
|
||||
assert(previousCell, 'expected previous cell enter')
|
||||
previousCell.end = Object.assign({}, getPoint(context.events, range[0]))
|
||||
map.add(range[0], 0, [['exit', previousCell, context]])
|
||||
}
|
||||
|
||||
// Insert enter of this cell.
|
||||
//
|
||||
// ```markdown
|
||||
// > | | aa | bb | cc |
|
||||
// ^-- enter
|
||||
// ^^^^-- this cell
|
||||
// ```
|
||||
const now = getPoint(context.events, range[1])
|
||||
previousCell = {
|
||||
type: groupName,
|
||||
start: Object.assign({}, now),
|
||||
// Note: correct end is set later.
|
||||
end: Object.assign({}, now)
|
||||
}
|
||||
map.add(range[1], 0, [['enter', previousCell, context]])
|
||||
|
||||
// Insert text start at first data start and end at last data end, and
|
||||
// remove events between.
|
||||
//
|
||||
// ```markdown
|
||||
// > | | aa | bb | cc |
|
||||
// ^-- enter
|
||||
// ^-- exit
|
||||
// ^^^^-- this cell
|
||||
// ```
|
||||
if (range[2] !== 0) {
|
||||
const relatedStart = getPoint(context.events, range[2])
|
||||
const relatedEnd = getPoint(context.events, range[3])
|
||||
/** @type {Token} */
|
||||
const valueToken = {
|
||||
type: valueName,
|
||||
start: Object.assign({}, relatedStart),
|
||||
end: Object.assign({}, relatedEnd)
|
||||
}
|
||||
map.add(range[2], 0, [['enter', valueToken, context]])
|
||||
assert(range[3] !== 0)
|
||||
|
||||
if (rowKind !== 2) {
|
||||
// Fix positional info on remaining events
|
||||
const start = context.events[range[2]]
|
||||
const end = context.events[range[3]]
|
||||
start[1].end = Object.assign({}, end[1].end)
|
||||
start[1].type = types.chunkText
|
||||
start[1].contentType = constants.contentTypeText
|
||||
|
||||
// Remove if needed.
|
||||
if (range[3] > range[2] + 1) {
|
||||
const a = range[2] + 1
|
||||
const b = range[3] - range[2] - 1
|
||||
map.add(a, b, [])
|
||||
}
|
||||
}
|
||||
|
||||
map.add(range[3] + 1, 0, [['exit', valueToken, context]])
|
||||
}
|
||||
|
||||
// Insert an exit for the last cell, if at the row end.
|
||||
//
|
||||
// ```markdown
|
||||
// > | | aa | bb | cc |
|
||||
// ^-- exit
|
||||
// ^^^^^^-- this cell (the last one contains two “between” parts)
|
||||
// ```
|
||||
if (rowEnd !== undefined) {
|
||||
previousCell.end = Object.assign({}, getPoint(context.events, rowEnd))
|
||||
map.add(rowEnd, 0, [['exit', previousCell, context]])
|
||||
previousCell = undefined
|
||||
}
|
||||
|
||||
return previousCell
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate table end (and table body end).
|
||||
*
|
||||
* @param {Readonly<EditMap>} map
|
||||
* @param {Readonly<TokenizeContext>} context
|
||||
* @param {number} index
|
||||
* @param {Token} table
|
||||
* @param {Token | undefined} tableBody
|
||||
*/
|
||||
// eslint-disable-next-line max-params
|
||||
function flushTableEnd(map, context, index, table, tableBody) {
|
||||
/** @type {Array<Event>} */
|
||||
const exits = []
|
||||
const related = getPoint(context.events, index)
|
||||
|
||||
if (tableBody) {
|
||||
tableBody.end = Object.assign({}, related)
|
||||
exits.push(['exit', tableBody, context])
|
||||
}
|
||||
|
||||
table.end = Object.assign({}, related)
|
||||
exits.push(['exit', table, context])
|
||||
|
||||
map.add(index + 1, 0, exits)
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Readonly<Array<Event>>} events
|
||||
* @param {number} index
|
||||
* @returns {Readonly<Point>}
|
||||
*/
|
||||
function getPoint(events, index) {
|
||||
const event = events[index]
|
||||
const side = event[0] === 'enter' ? 'start' : 'end'
|
||||
return event[1][side]
|
||||
}
|
55
node_modules/micromark-extension-gfm-table/index.d.ts
generated
vendored
Normal file
55
node_modules/micromark-extension-gfm-table/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
import type {Align} from './lib/infer.js'
|
||||
|
||||
export {gfmTableHtml} from './lib/html.js'
|
||||
export {gfmTable} from './lib/syntax.js'
|
||||
|
||||
/**
|
||||
* Augment types.
|
||||
*/
|
||||
declare module 'micromark-util-types' {
|
||||
/**
|
||||
* State tracked to compile events as HTML,
|
||||
* extended by `micromark-extension-gfm-table`.
|
||||
*/
|
||||
interface CompileData {
|
||||
/**
|
||||
* Alignment of current table.
|
||||
*/
|
||||
tableAlign?: Array<Align> | undefined
|
||||
/**
|
||||
* Current table column.
|
||||
*/
|
||||
tableColumn?: number | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Augment token;
|
||||
* `align` is patched on `table` tokens by
|
||||
* `micromark-extension-gfm-table`.
|
||||
*/
|
||||
interface Token {
|
||||
/**
|
||||
* Alignment of current table.
|
||||
*/
|
||||
_align?: Array<Align> | undefined
|
||||
}
|
||||
|
||||
/**
|
||||
* Map of allowed token types,
|
||||
* extended by `micromark-extension-gfm-table`.
|
||||
*/
|
||||
interface TokenTypeMap {
|
||||
tableBody: 'tableBody'
|
||||
tableCellDivider: 'tableCellDivider'
|
||||
tableContent: 'tableContent'
|
||||
tableData: 'tableData'
|
||||
tableDelimiterFiller: 'tableDelimiterFiller'
|
||||
tableDelimiterMarker: 'tableDelimiterMarker'
|
||||
tableDelimiterRow: 'tableDelimiterRow'
|
||||
tableDelimiter: 'tableDelimiter'
|
||||
tableHeader: 'tableHeader'
|
||||
tableHead: 'tableHead'
|
||||
tableRow: 'tableRow'
|
||||
table: 'table'
|
||||
}
|
||||
}
|
2
node_modules/micromark-extension-gfm-table/index.js
generated
vendored
Normal file
2
node_modules/micromark-extension-gfm-table/index.js
generated
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
export { gfmTableHtml } from './lib/html.js';
|
||||
export { gfmTable } from './lib/syntax.js';
|
38
node_modules/micromark-extension-gfm-table/lib/edit-map.d.ts
generated
vendored
Normal file
38
node_modules/micromark-extension-gfm-table/lib/edit-map.d.ts
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @import {Event} from 'micromark-util-types'
|
||||
*/
|
||||
/**
|
||||
* @typedef {[number, number, Array<Event>]} Change
|
||||
* @typedef {[number, number, number]} Jump
|
||||
*/
|
||||
/**
|
||||
* Tracks a bunch of edits.
|
||||
*/
|
||||
export class EditMap {
|
||||
/**
|
||||
* Record of changes.
|
||||
*
|
||||
* @type {Array<Change>}
|
||||
*/
|
||||
map: Array<Change>;
|
||||
/**
|
||||
* Create an edit: a remove and/or add at a certain place.
|
||||
*
|
||||
* @param {number} index
|
||||
* @param {number} remove
|
||||
* @param {Array<Event>} add
|
||||
* @returns {undefined}
|
||||
*/
|
||||
add(index: number, remove: number, add: Array<Event>): undefined;
|
||||
/**
|
||||
* Done, change the events.
|
||||
*
|
||||
* @param {Array<Event>} events
|
||||
* @returns {undefined}
|
||||
*/
|
||||
consume(events: Array<Event>): undefined;
|
||||
}
|
||||
export type Change = [number, number, Array<Event>];
|
||||
export type Jump = [number, number, number];
|
||||
import type { Event } from 'micromark-util-types';
|
||||
//# sourceMappingURL=edit-map.d.ts.map
|
1
node_modules/micromark-extension-gfm-table/lib/edit-map.d.ts.map
generated
vendored
Normal file
1
node_modules/micromark-extension-gfm-table/lib/edit-map.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"edit-map.d.ts","sourceRoot":"","sources":["edit-map.js"],"names":[],"mappings":"AAAA;;GAEG;AAeH;;;GAGG;AAEH;;GAEG;AACH;IAKI;;;;OAIG;IACH,KAFU,KAAK,CAAC,MAAM,CAAC,CAEV;IAGf;;;;;;;OAOG;IACH,WALW,MAAM,UACN,MAAM,OACN,KAAK,CAAC,KAAK,CAAC,GACV,SAAS,CAIrB;IAeD;;;;;OAKG;IACH,gBAHW,KAAK,CAAC,KAAK,CAAC,GACV,SAAS,CA2DrB;CACF;qBA7GY,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,CAAC,KAAK,CAAC,CAAC;mBAC9B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;2BAlBb,sBAAsB"}
|
202
node_modules/micromark-extension-gfm-table/lib/edit-map.js
generated
vendored
Normal file
202
node_modules/micromark-extension-gfm-table/lib/edit-map.js
generated
vendored
Normal file
@@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @import {Event} from 'micromark-util-types'
|
||||
*/
|
||||
|
||||
// Port of `edit_map.rs` from `markdown-rs`.
|
||||
// This should move to `markdown-js` later.
|
||||
|
||||
// Deal with several changes in events, batching them together.
|
||||
//
|
||||
// Preferably, changes should be kept to a minimum.
|
||||
// Sometimes, it’s needed to change the list of events, because parsing can be
|
||||
// messy, and it helps to expose a cleaner interface of events to the compiler
|
||||
// and other users.
|
||||
// It can also help to merge many adjacent similar events.
|
||||
// And, in other cases, it’s needed to parse subcontent: pass some events
|
||||
// through another tokenizer and inject the result.
|
||||
|
||||
/**
|
||||
* @typedef {[number, number, Array<Event>]} Change
|
||||
* @typedef {[number, number, number]} Jump
|
||||
*/
|
||||
|
||||
/**
|
||||
* Tracks a bunch of edits.
|
||||
*/
|
||||
export class EditMap {
|
||||
/**
|
||||
* Create a new edit map.
|
||||
*/
|
||||
constructor() {
|
||||
/**
|
||||
* Record of changes.
|
||||
*
|
||||
* @type {Array<Change>}
|
||||
*/
|
||||
this.map = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an edit: a remove and/or add at a certain place.
|
||||
*
|
||||
* @param {number} index
|
||||
* @param {number} remove
|
||||
* @param {Array<Event>} add
|
||||
* @returns {undefined}
|
||||
*/
|
||||
add(index, remove, add) {
|
||||
addImplementation(this, index, remove, add);
|
||||
}
|
||||
|
||||
// To do: add this when moving to `micromark`.
|
||||
// /**
|
||||
// * Create an edit: but insert `add` before existing additions.
|
||||
// *
|
||||
// * @param {number} index
|
||||
// * @param {number} remove
|
||||
// * @param {Array<Event>} add
|
||||
// * @returns {undefined}
|
||||
// */
|
||||
// addBefore(index, remove, add) {
|
||||
// addImplementation(this, index, remove, add, true)
|
||||
// }
|
||||
|
||||
/**
|
||||
* Done, change the events.
|
||||
*
|
||||
* @param {Array<Event>} events
|
||||
* @returns {undefined}
|
||||
*/
|
||||
consume(events) {
|
||||
this.map.sort(function (a, b) {
|
||||
return a[0] - b[0];
|
||||
});
|
||||
|
||||
/* c8 ignore next 3 -- `resolve` is never called without tables, so without edits. */
|
||||
if (this.map.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// To do: if links are added in events, like they are in `markdown-rs`,
|
||||
// this is needed.
|
||||
// // Calculate jumps: where items in the current list move to.
|
||||
// /** @type {Array<Jump>} */
|
||||
// const jumps = []
|
||||
// let index = 0
|
||||
// let addAcc = 0
|
||||
// let removeAcc = 0
|
||||
// while (index < this.map.length) {
|
||||
// const [at, remove, add] = this.map[index]
|
||||
// removeAcc += remove
|
||||
// addAcc += add.length
|
||||
// jumps.push([at, removeAcc, addAcc])
|
||||
// index += 1
|
||||
// }
|
||||
//
|
||||
// . shiftLinks(events, jumps)
|
||||
|
||||
let index = this.map.length;
|
||||
/** @type {Array<Array<Event>>} */
|
||||
const vecs = [];
|
||||
while (index > 0) {
|
||||
index -= 1;
|
||||
vecs.push(events.slice(this.map[index][0] + this.map[index][1]), this.map[index][2]);
|
||||
|
||||
// Truncate rest.
|
||||
events.length = this.map[index][0];
|
||||
}
|
||||
vecs.push(events.slice());
|
||||
events.length = 0;
|
||||
let slice = vecs.pop();
|
||||
while (slice) {
|
||||
for (const element of slice) {
|
||||
events.push(element);
|
||||
}
|
||||
slice = vecs.pop();
|
||||
}
|
||||
|
||||
// Truncate everything.
|
||||
this.map.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an edit.
|
||||
*
|
||||
* @param {EditMap} editMap
|
||||
* @param {number} at
|
||||
* @param {number} remove
|
||||
* @param {Array<Event>} add
|
||||
* @returns {undefined}
|
||||
*/
|
||||
function addImplementation(editMap, at, remove, add) {
|
||||
let index = 0;
|
||||
|
||||
/* c8 ignore next 3 -- `resolve` is never called without tables, so without edits. */
|
||||
if (remove === 0 && add.length === 0) {
|
||||
return;
|
||||
}
|
||||
while (index < editMap.map.length) {
|
||||
if (editMap.map[index][0] === at) {
|
||||
editMap.map[index][1] += remove;
|
||||
|
||||
// To do: before not used by tables, use when moving to micromark.
|
||||
// if (before) {
|
||||
// add.push(...editMap.map[index][2])
|
||||
// editMap.map[index][2] = add
|
||||
// } else {
|
||||
editMap.map[index][2].push(...add);
|
||||
// }
|
||||
|
||||
return;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
editMap.map.push([at, remove, add]);
|
||||
}
|
||||
|
||||
// /**
|
||||
// * Shift `previous` and `next` links according to `jumps`.
|
||||
// *
|
||||
// * This fixes links in case there are events removed or added between them.
|
||||
// *
|
||||
// * @param {Array<Event>} events
|
||||
// * @param {Array<Jump>} jumps
|
||||
// */
|
||||
// function shiftLinks(events, jumps) {
|
||||
// let jumpIndex = 0
|
||||
// let index = 0
|
||||
// let add = 0
|
||||
// let rm = 0
|
||||
|
||||
// while (index < events.length) {
|
||||
// const rmCurr = rm
|
||||
|
||||
// while (jumpIndex < jumps.length && jumps[jumpIndex][0] <= index) {
|
||||
// add = jumps[jumpIndex][2]
|
||||
// rm = jumps[jumpIndex][1]
|
||||
// jumpIndex += 1
|
||||
// }
|
||||
|
||||
// // Ignore items that will be removed.
|
||||
// if (rm > rmCurr) {
|
||||
// index += rm - rmCurr
|
||||
// } else {
|
||||
// // ?
|
||||
// // if let Some(link) = &events[index].link {
|
||||
// // if let Some(next) = link.next {
|
||||
// // events[next].link.as_mut().unwrap().previous = Some(index + add - rm);
|
||||
// // while jumpIndex < jumps.len() && jumps[jumpIndex].0 <= next {
|
||||
// // add = jumps[jumpIndex].2;
|
||||
// // rm = jumps[jumpIndex].1;
|
||||
// // jumpIndex += 1;
|
||||
// // }
|
||||
// // events[index].link.as_mut().unwrap().next = Some(next + add - rm);
|
||||
// // index = next;
|
||||
// // continue;
|
||||
// // }
|
||||
// // }
|
||||
// index += 1
|
||||
// }
|
||||
// }
|
||||
// }
|
11
node_modules/micromark-extension-gfm-table/lib/html.d.ts
generated
vendored
Normal file
11
node_modules/micromark-extension-gfm-table/lib/html.d.ts
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Create an HTML extension for `micromark` to support GitHub tables when
|
||||
* serializing to HTML.
|
||||
*
|
||||
* @returns {HtmlExtension}
|
||||
* Extension for `micromark` that can be passed in `htmlExtensions` to
|
||||
* support GitHub tables when serializing to HTML.
|
||||
*/
|
||||
export function gfmTableHtml(): HtmlExtension;
|
||||
import type { HtmlExtension } from 'micromark-util-types';
|
||||
//# sourceMappingURL=html.d.ts.map
|
1
node_modules/micromark-extension-gfm-table/lib/html.d.ts.map
generated
vendored
Normal file
1
node_modules/micromark-extension-gfm-table/lib/html.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"html.d.ts","sourceRoot":"","sources":["html.js"],"names":[],"mappings":"AAeA;;;;;;;GAOG;AACH,gCAJa,aAAa,CAsHzB;mCAxI+B,sBAAsB"}
|
130
node_modules/micromark-extension-gfm-table/lib/html.js
generated
vendored
Normal file
130
node_modules/micromark-extension-gfm-table/lib/html.js
generated
vendored
Normal file
@@ -0,0 +1,130 @@
|
||||
/**
|
||||
* @import {HtmlExtension} from 'micromark-util-types'
|
||||
*/
|
||||
|
||||
const alignment = {
|
||||
none: '',
|
||||
left: ' align="left"',
|
||||
right: ' align="right"',
|
||||
center: ' align="center"'
|
||||
};
|
||||
|
||||
// To do: micromark@5: use `infer` here, when all events are exposed.
|
||||
|
||||
/**
|
||||
* Create an HTML extension for `micromark` to support GitHub tables when
|
||||
* serializing to HTML.
|
||||
*
|
||||
* @returns {HtmlExtension}
|
||||
* Extension for `micromark` that can be passed in `htmlExtensions` to
|
||||
* support GitHub tables when serializing to HTML.
|
||||
*/
|
||||
export function gfmTableHtml() {
|
||||
return {
|
||||
enter: {
|
||||
table(token) {
|
||||
const tableAlign = token._align;
|
||||
this.lineEndingIfNeeded();
|
||||
this.tag('<table>');
|
||||
this.setData('tableAlign', tableAlign);
|
||||
},
|
||||
tableBody() {
|
||||
this.tag('<tbody>');
|
||||
},
|
||||
tableData() {
|
||||
const tableAlign = this.getData('tableAlign');
|
||||
const tableColumn = this.getData('tableColumn');
|
||||
const align = alignment[tableAlign[tableColumn]];
|
||||
if (align === undefined) {
|
||||
// Capture results to ignore them.
|
||||
this.buffer();
|
||||
} else {
|
||||
this.lineEndingIfNeeded();
|
||||
this.tag('<td' + align + '>');
|
||||
}
|
||||
},
|
||||
tableHead() {
|
||||
this.lineEndingIfNeeded();
|
||||
this.tag('<thead>');
|
||||
},
|
||||
tableHeader() {
|
||||
const tableAlign = this.getData('tableAlign');
|
||||
const tableColumn = this.getData('tableColumn');
|
||||
const align = alignment[tableAlign[tableColumn]];
|
||||
this.lineEndingIfNeeded();
|
||||
this.tag('<th' + align + '>');
|
||||
},
|
||||
tableRow() {
|
||||
this.setData('tableColumn', 0);
|
||||
this.lineEndingIfNeeded();
|
||||
this.tag('<tr>');
|
||||
}
|
||||
},
|
||||
exit: {
|
||||
// Overwrite the default code text data handler to unescape escaped pipes when
|
||||
// they are in tables.
|
||||
codeTextData(token) {
|
||||
let value = this.sliceSerialize(token);
|
||||
if (this.getData('tableAlign')) {
|
||||
value = value.replace(/\\([\\|])/g, replace);
|
||||
}
|
||||
this.raw(this.encode(value));
|
||||
},
|
||||
table() {
|
||||
this.setData('tableAlign');
|
||||
// Note: we don’t set `slurpAllLineEndings` anymore, in delimiter rows,
|
||||
// but we do need to reset it to match a funky newline GH generates for
|
||||
// list items combined with tables.
|
||||
this.setData('slurpAllLineEndings');
|
||||
this.lineEndingIfNeeded();
|
||||
this.tag('</table>');
|
||||
},
|
||||
tableBody() {
|
||||
this.lineEndingIfNeeded();
|
||||
this.tag('</tbody>');
|
||||
},
|
||||
tableData() {
|
||||
const tableAlign = this.getData('tableAlign');
|
||||
const tableColumn = this.getData('tableColumn');
|
||||
if (tableColumn in tableAlign) {
|
||||
this.tag('</td>');
|
||||
this.setData('tableColumn', tableColumn + 1);
|
||||
} else {
|
||||
// Stop capturing.
|
||||
this.resume();
|
||||
}
|
||||
},
|
||||
tableHead() {
|
||||
this.lineEndingIfNeeded();
|
||||
this.tag('</thead>');
|
||||
},
|
||||
tableHeader() {
|
||||
const tableColumn = this.getData('tableColumn');
|
||||
this.tag('</th>');
|
||||
this.setData('tableColumn', tableColumn + 1);
|
||||
},
|
||||
tableRow() {
|
||||
const tableAlign = this.getData('tableAlign');
|
||||
let tableColumn = this.getData('tableColumn');
|
||||
while (tableColumn < tableAlign.length) {
|
||||
this.lineEndingIfNeeded();
|
||||
this.tag('<td' + alignment[tableAlign[tableColumn]] + '></td>');
|
||||
tableColumn++;
|
||||
}
|
||||
this.setData('tableColumn', tableColumn);
|
||||
this.lineEndingIfNeeded();
|
||||
this.tag('</tr>');
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} $0
|
||||
* @param {string} $1
|
||||
* @returns {string}
|
||||
*/
|
||||
function replace($0, $1) {
|
||||
// Pipes work, backslashes don’t (but can’t escape pipes).
|
||||
return $1 === '|' ? $1 : $0;
|
||||
}
|
14
node_modules/micromark-extension-gfm-table/lib/infer.d.ts
generated
vendored
Normal file
14
node_modules/micromark-extension-gfm-table/lib/infer.d.ts
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Figure out the alignment of a GFM table.
|
||||
*
|
||||
* @param {Readonly<Array<Event>>} events
|
||||
* List of events.
|
||||
* @param {number} index
|
||||
* Table enter event.
|
||||
* @returns {Array<Align>}
|
||||
* List of aligns.
|
||||
*/
|
||||
export function gfmTableAlign(events: Readonly<Array<Event>>, index: number): Array<Align>;
|
||||
export type Align = "center" | "left" | "none" | "right";
|
||||
import type { Event } from 'micromark-util-types';
|
||||
//# sourceMappingURL=infer.d.ts.map
|
1
node_modules/micromark-extension-gfm-table/lib/infer.d.ts.map
generated
vendored
Normal file
1
node_modules/micromark-extension-gfm-table/lib/infer.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"infer.d.ts","sourceRoot":"","sources":["infer.js"],"names":[],"mappings":"AAUA;;;;;;;;;GASG;AACH,sCAPW,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,SAEtB,MAAM,GAEJ,KAAK,CAAC,KAAK,CAAC,CA8CxB;oBA1DY,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO;2BAJzB,sBAAsB"}
|
52
node_modules/micromark-extension-gfm-table/lib/infer.js
generated
vendored
Normal file
52
node_modules/micromark-extension-gfm-table/lib/infer.js
generated
vendored
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @import {Event} from 'micromark-util-types'
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {'center' | 'left' | 'none' | 'right'} Align
|
||||
*/
|
||||
|
||||
/**
|
||||
* Figure out the alignment of a GFM table.
|
||||
*
|
||||
* @param {Readonly<Array<Event>>} events
|
||||
* List of events.
|
||||
* @param {number} index
|
||||
* Table enter event.
|
||||
* @returns {Array<Align>}
|
||||
* List of aligns.
|
||||
*/
|
||||
export function gfmTableAlign(events, index) {
|
||||
let inDelimiterRow = false;
|
||||
/** @type {Array<Align>} */
|
||||
const align = [];
|
||||
while (index < events.length) {
|
||||
const event = events[index];
|
||||
if (inDelimiterRow) {
|
||||
if (event[0] === 'enter') {
|
||||
// Start of alignment value: set a new column.
|
||||
// To do: `markdown-rs` uses `tableDelimiterCellValue`.
|
||||
if (event[1].type === 'tableContent') {
|
||||
align.push(events[index + 1][1].type === 'tableDelimiterMarker' ? 'left' : 'none');
|
||||
}
|
||||
}
|
||||
// Exits:
|
||||
// End of alignment value: change the column.
|
||||
// To do: `markdown-rs` uses `tableDelimiterCellValue`.
|
||||
else if (event[1].type === 'tableContent') {
|
||||
if (events[index - 1][1].type === 'tableDelimiterMarker') {
|
||||
const alignIndex = align.length - 1;
|
||||
align[alignIndex] = align[alignIndex] === 'left' ? 'center' : 'right';
|
||||
}
|
||||
}
|
||||
// Done!
|
||||
else if (event[1].type === 'tableDelimiterRow') {
|
||||
break;
|
||||
}
|
||||
} else if (event[0] === 'enter' && event[1].type === 'tableDelimiterRow') {
|
||||
inDelimiterRow = true;
|
||||
}
|
||||
index += 1;
|
||||
}
|
||||
return align;
|
||||
}
|
18
node_modules/micromark-extension-gfm-table/lib/syntax.d.ts
generated
vendored
Normal file
18
node_modules/micromark-extension-gfm-table/lib/syntax.d.ts
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Create an HTML extension for `micromark` to support GitHub tables syntax.
|
||||
*
|
||||
* @returns {Extension}
|
||||
* Extension for `micromark` that can be passed in `extensions` to enable GFM
|
||||
* table syntax.
|
||||
*/
|
||||
export function gfmTable(): Extension;
|
||||
/**
|
||||
* Cell info.
|
||||
*/
|
||||
export type Range = [number, number, number, number];
|
||||
/**
|
||||
* Where we are: `1` for head row, `2` for delimiter row, `3` for body row.
|
||||
*/
|
||||
export type RowKind = 0 | 1 | 2 | 3;
|
||||
import type { Extension } from 'micromark-util-types';
|
||||
//# sourceMappingURL=syntax.d.ts.map
|
1
node_modules/micromark-extension-gfm-table/lib/syntax.d.ts.map
generated
vendored
Normal file
1
node_modules/micromark-extension-gfm-table/lib/syntax.d.ts.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"syntax.d.ts","sourceRoot":"","sources":["syntax.js"],"names":[],"mappings":"AAuBA;;;;;;GAMG;AACH,4BAJa,SAAS,CAUrB;;;;oBA/BY,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC;;;;sBAGhC,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC;+BAPoE,sBAAsB"}
|
819
node_modules/micromark-extension-gfm-table/lib/syntax.js
generated
vendored
Normal file
819
node_modules/micromark-extension-gfm-table/lib/syntax.js
generated
vendored
Normal file
@@ -0,0 +1,819 @@
|
||||
/**
|
||||
* @import {Event, Extension, Point, Resolver, State, Token, TokenizeContext, Tokenizer} from 'micromark-util-types'
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {[number, number, number, number]} Range
|
||||
* Cell info.
|
||||
*
|
||||
* @typedef {0 | 1 | 2 | 3} RowKind
|
||||
* Where we are: `1` for head row, `2` for delimiter row, `3` for body row.
|
||||
*/
|
||||
|
||||
import { factorySpace } from 'micromark-factory-space';
|
||||
import { markdownLineEnding, markdownLineEndingOrSpace, markdownSpace } from 'micromark-util-character';
|
||||
import { EditMap } from './edit-map.js';
|
||||
import { gfmTableAlign } from './infer.js';
|
||||
|
||||
/**
|
||||
* Create an HTML extension for `micromark` to support GitHub tables syntax.
|
||||
*
|
||||
* @returns {Extension}
|
||||
* Extension for `micromark` that can be passed in `extensions` to enable GFM
|
||||
* table syntax.
|
||||
*/
|
||||
export function gfmTable() {
|
||||
return {
|
||||
flow: {
|
||||
null: {
|
||||
name: 'table',
|
||||
tokenize: tokenizeTable,
|
||||
resolveAll: resolveTable
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @this {TokenizeContext}
|
||||
* @type {Tokenizer}
|
||||
*/
|
||||
function tokenizeTable(effects, ok, nok) {
|
||||
const self = this;
|
||||
let size = 0;
|
||||
let sizeB = 0;
|
||||
/** @type {boolean | undefined} */
|
||||
let seen;
|
||||
return start;
|
||||
|
||||
/**
|
||||
* Start of a GFM table.
|
||||
*
|
||||
* If there is a valid table row or table head before, then we try to parse
|
||||
* another row.
|
||||
* Otherwise, we try to parse a head.
|
||||
*
|
||||
* ```markdown
|
||||
* > | | a |
|
||||
* ^
|
||||
* | | - |
|
||||
* > | | b |
|
||||
* ^
|
||||
* ```
|
||||
* @type {State}
|
||||
*/
|
||||
function start(code) {
|
||||
let index = self.events.length - 1;
|
||||
while (index > -1) {
|
||||
const type = self.events[index][1].type;
|
||||
if (type === "lineEnding" ||
|
||||
// Note: markdown-rs uses `whitespace` instead of `linePrefix`
|
||||
type === "linePrefix") index--;else break;
|
||||
}
|
||||
const tail = index > -1 ? self.events[index][1].type : null;
|
||||
const next = tail === 'tableHead' || tail === 'tableRow' ? bodyRowStart : headRowBefore;
|
||||
|
||||
// Don’t allow lazy body rows.
|
||||
if (next === bodyRowStart && self.parser.lazy[self.now().line]) {
|
||||
return nok(code);
|
||||
}
|
||||
return next(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Before table head row.
|
||||
*
|
||||
* ```markdown
|
||||
* > | | a |
|
||||
* ^
|
||||
* | | - |
|
||||
* | | b |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headRowBefore(code) {
|
||||
effects.enter('tableHead');
|
||||
effects.enter('tableRow');
|
||||
return headRowStart(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Before table head row, after whitespace.
|
||||
*
|
||||
* ```markdown
|
||||
* > | | a |
|
||||
* ^
|
||||
* | | - |
|
||||
* | | b |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headRowStart(code) {
|
||||
if (code === 124) {
|
||||
return headRowBreak(code);
|
||||
}
|
||||
|
||||
// To do: micromark-js should let us parse our own whitespace in extensions,
|
||||
// like `markdown-rs`:
|
||||
//
|
||||
// ```js
|
||||
// // 4+ spaces.
|
||||
// if (markdownSpace(code)) {
|
||||
// return nok(code)
|
||||
// }
|
||||
// ```
|
||||
|
||||
seen = true;
|
||||
// Count the first character, that isn’t a pipe, double.
|
||||
sizeB += 1;
|
||||
return headRowBreak(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* At break in table head row.
|
||||
*
|
||||
* ```markdown
|
||||
* > | | a |
|
||||
* ^
|
||||
* ^
|
||||
* ^
|
||||
* | | - |
|
||||
* | | b |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headRowBreak(code) {
|
||||
if (code === null) {
|
||||
// Note: in `markdown-rs`, we need to reset, in `micromark-js` we don‘t.
|
||||
return nok(code);
|
||||
}
|
||||
if (markdownLineEnding(code)) {
|
||||
// If anything other than one pipe (ignoring whitespace) was used, it’s fine.
|
||||
if (sizeB > 1) {
|
||||
sizeB = 0;
|
||||
// To do: check if this works.
|
||||
// Feel free to interrupt:
|
||||
self.interrupt = true;
|
||||
effects.exit('tableRow');
|
||||
effects.enter("lineEnding");
|
||||
effects.consume(code);
|
||||
effects.exit("lineEnding");
|
||||
return headDelimiterStart;
|
||||
}
|
||||
|
||||
// Note: in `markdown-rs`, we need to reset, in `micromark-js` we don‘t.
|
||||
return nok(code);
|
||||
}
|
||||
if (markdownSpace(code)) {
|
||||
// To do: check if this is fine.
|
||||
// effects.attempt(State::Next(StateName::GfmTableHeadRowBreak), State::Nok)
|
||||
// State::Retry(space_or_tab(tokenizer))
|
||||
return factorySpace(effects, headRowBreak, "whitespace")(code);
|
||||
}
|
||||
sizeB += 1;
|
||||
if (seen) {
|
||||
seen = false;
|
||||
// Header cell count.
|
||||
size += 1;
|
||||
}
|
||||
if (code === 124) {
|
||||
effects.enter('tableCellDivider');
|
||||
effects.consume(code);
|
||||
effects.exit('tableCellDivider');
|
||||
// Whether a delimiter was seen.
|
||||
seen = true;
|
||||
return headRowBreak;
|
||||
}
|
||||
|
||||
// Anything else is cell data.
|
||||
effects.enter("data");
|
||||
return headRowData(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* In table head row data.
|
||||
*
|
||||
* ```markdown
|
||||
* > | | a |
|
||||
* ^
|
||||
* | | - |
|
||||
* | | b |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headRowData(code) {
|
||||
if (code === null || code === 124 || markdownLineEndingOrSpace(code)) {
|
||||
effects.exit("data");
|
||||
return headRowBreak(code);
|
||||
}
|
||||
effects.consume(code);
|
||||
return code === 92 ? headRowEscape : headRowData;
|
||||
}
|
||||
|
||||
/**
|
||||
* In table head row escape.
|
||||
*
|
||||
* ```markdown
|
||||
* > | | a\-b |
|
||||
* ^
|
||||
* | | ---- |
|
||||
* | | c |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headRowEscape(code) {
|
||||
if (code === 92 || code === 124) {
|
||||
effects.consume(code);
|
||||
return headRowData;
|
||||
}
|
||||
return headRowData(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Before delimiter row.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | - |
|
||||
* ^
|
||||
* | | b |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterStart(code) {
|
||||
// Reset `interrupt`.
|
||||
self.interrupt = false;
|
||||
|
||||
// Note: in `markdown-rs`, we need to handle piercing here too.
|
||||
if (self.parser.lazy[self.now().line]) {
|
||||
return nok(code);
|
||||
}
|
||||
effects.enter('tableDelimiterRow');
|
||||
// Track if we’ve seen a `:` or `|`.
|
||||
seen = false;
|
||||
if (markdownSpace(code)) {
|
||||
return factorySpace(effects, headDelimiterBefore, "linePrefix", self.parser.constructs.disable.null.includes('codeIndented') ? undefined : 4)(code);
|
||||
}
|
||||
return headDelimiterBefore(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Before delimiter row, after optional whitespace.
|
||||
*
|
||||
* Reused when a `|` is found later, to parse another cell.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | - |
|
||||
* ^
|
||||
* | | b |
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterBefore(code) {
|
||||
if (code === 45 || code === 58) {
|
||||
return headDelimiterValueBefore(code);
|
||||
}
|
||||
if (code === 124) {
|
||||
seen = true;
|
||||
// If we start with a pipe, we open a cell marker.
|
||||
effects.enter('tableCellDivider');
|
||||
effects.consume(code);
|
||||
effects.exit('tableCellDivider');
|
||||
return headDelimiterCellBefore;
|
||||
}
|
||||
|
||||
// More whitespace / empty row not allowed at start.
|
||||
return headDelimiterNok(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* After `|`, before delimiter cell.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | - |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterCellBefore(code) {
|
||||
if (markdownSpace(code)) {
|
||||
return factorySpace(effects, headDelimiterValueBefore, "whitespace")(code);
|
||||
}
|
||||
return headDelimiterValueBefore(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Before delimiter cell value.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | - |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterValueBefore(code) {
|
||||
// Align: left.
|
||||
if (code === 58) {
|
||||
sizeB += 1;
|
||||
seen = true;
|
||||
effects.enter('tableDelimiterMarker');
|
||||
effects.consume(code);
|
||||
effects.exit('tableDelimiterMarker');
|
||||
return headDelimiterLeftAlignmentAfter;
|
||||
}
|
||||
|
||||
// Align: none.
|
||||
if (code === 45) {
|
||||
sizeB += 1;
|
||||
// To do: seems weird that this *isn’t* left aligned, but that state is used?
|
||||
return headDelimiterLeftAlignmentAfter(code);
|
||||
}
|
||||
if (code === null || markdownLineEnding(code)) {
|
||||
return headDelimiterCellAfter(code);
|
||||
}
|
||||
return headDelimiterNok(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* After delimiter cell left alignment marker.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | :- |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterLeftAlignmentAfter(code) {
|
||||
if (code === 45) {
|
||||
effects.enter('tableDelimiterFiller');
|
||||
return headDelimiterFiller(code);
|
||||
}
|
||||
|
||||
// Anything else is not ok after the left-align colon.
|
||||
return headDelimiterNok(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* In delimiter cell filler.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | - |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterFiller(code) {
|
||||
if (code === 45) {
|
||||
effects.consume(code);
|
||||
return headDelimiterFiller;
|
||||
}
|
||||
|
||||
// Align is `center` if it was `left`, `right` otherwise.
|
||||
if (code === 58) {
|
||||
seen = true;
|
||||
effects.exit('tableDelimiterFiller');
|
||||
effects.enter('tableDelimiterMarker');
|
||||
effects.consume(code);
|
||||
effects.exit('tableDelimiterMarker');
|
||||
return headDelimiterRightAlignmentAfter;
|
||||
}
|
||||
effects.exit('tableDelimiterFiller');
|
||||
return headDelimiterRightAlignmentAfter(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* After delimiter cell right alignment marker.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | -: |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterRightAlignmentAfter(code) {
|
||||
if (markdownSpace(code)) {
|
||||
return factorySpace(effects, headDelimiterCellAfter, "whitespace")(code);
|
||||
}
|
||||
return headDelimiterCellAfter(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* After delimiter cell.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | -: |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterCellAfter(code) {
|
||||
if (code === 124) {
|
||||
return headDelimiterBefore(code);
|
||||
}
|
||||
if (code === null || markdownLineEnding(code)) {
|
||||
// Exit when:
|
||||
// * there was no `:` or `|` at all (it’s a thematic break or setext
|
||||
// underline instead)
|
||||
// * the header cell count is not the delimiter cell count
|
||||
if (!seen || size !== sizeB) {
|
||||
return headDelimiterNok(code);
|
||||
}
|
||||
|
||||
// Note: in markdown-rs`, a reset is needed here.
|
||||
effects.exit('tableDelimiterRow');
|
||||
effects.exit('tableHead');
|
||||
// To do: in `markdown-rs`, resolvers need to be registered manually.
|
||||
// effects.register_resolver(ResolveName::GfmTable)
|
||||
return ok(code);
|
||||
}
|
||||
return headDelimiterNok(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* In delimiter row, at a disallowed byte.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* > | | x |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function headDelimiterNok(code) {
|
||||
// Note: in `markdown-rs`, we need to reset, in `micromark-js` we don‘t.
|
||||
return nok(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* Before table body row.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* | | - |
|
||||
* > | | b |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function bodyRowStart(code) {
|
||||
// Note: in `markdown-rs` we need to manually take care of a prefix,
|
||||
// but in `micromark-js` that is done for us, so if we’re here, we’re
|
||||
// never at whitespace.
|
||||
effects.enter('tableRow');
|
||||
return bodyRowBreak(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* At break in table body row.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* | | - |
|
||||
* > | | b |
|
||||
* ^
|
||||
* ^
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function bodyRowBreak(code) {
|
||||
if (code === 124) {
|
||||
effects.enter('tableCellDivider');
|
||||
effects.consume(code);
|
||||
effects.exit('tableCellDivider');
|
||||
return bodyRowBreak;
|
||||
}
|
||||
if (code === null || markdownLineEnding(code)) {
|
||||
effects.exit('tableRow');
|
||||
return ok(code);
|
||||
}
|
||||
if (markdownSpace(code)) {
|
||||
return factorySpace(effects, bodyRowBreak, "whitespace")(code);
|
||||
}
|
||||
|
||||
// Anything else is cell content.
|
||||
effects.enter("data");
|
||||
return bodyRowData(code);
|
||||
}
|
||||
|
||||
/**
|
||||
* In table body row data.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* | | - |
|
||||
* > | | b |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function bodyRowData(code) {
|
||||
if (code === null || code === 124 || markdownLineEndingOrSpace(code)) {
|
||||
effects.exit("data");
|
||||
return bodyRowBreak(code);
|
||||
}
|
||||
effects.consume(code);
|
||||
return code === 92 ? bodyRowEscape : bodyRowData;
|
||||
}
|
||||
|
||||
/**
|
||||
* In table body row escape.
|
||||
*
|
||||
* ```markdown
|
||||
* | | a |
|
||||
* | | ---- |
|
||||
* > | | b\-c |
|
||||
* ^
|
||||
* ```
|
||||
*
|
||||
* @type {State}
|
||||
*/
|
||||
function bodyRowEscape(code) {
|
||||
if (code === 92 || code === 124) {
|
||||
effects.consume(code);
|
||||
return bodyRowData;
|
||||
}
|
||||
return bodyRowData(code);
|
||||
}
|
||||
}
|
||||
|
||||
/** @type {Resolver} */
|
||||
|
||||
function resolveTable(events, context) {
|
||||
let index = -1;
|
||||
let inFirstCellAwaitingPipe = true;
|
||||
/** @type {RowKind} */
|
||||
let rowKind = 0;
|
||||
/** @type {Range} */
|
||||
let lastCell = [0, 0, 0, 0];
|
||||
/** @type {Range} */
|
||||
let cell = [0, 0, 0, 0];
|
||||
let afterHeadAwaitingFirstBodyRow = false;
|
||||
let lastTableEnd = 0;
|
||||
/** @type {Token | undefined} */
|
||||
let currentTable;
|
||||
/** @type {Token | undefined} */
|
||||
let currentBody;
|
||||
/** @type {Token | undefined} */
|
||||
let currentCell;
|
||||
const map = new EditMap();
|
||||
while (++index < events.length) {
|
||||
const event = events[index];
|
||||
const token = event[1];
|
||||
if (event[0] === 'enter') {
|
||||
// Start of head.
|
||||
if (token.type === 'tableHead') {
|
||||
afterHeadAwaitingFirstBodyRow = false;
|
||||
|
||||
// Inject previous (body end and) table end.
|
||||
if (lastTableEnd !== 0) {
|
||||
flushTableEnd(map, context, lastTableEnd, currentTable, currentBody);
|
||||
currentBody = undefined;
|
||||
lastTableEnd = 0;
|
||||
}
|
||||
|
||||
// Inject table start.
|
||||
currentTable = {
|
||||
type: 'table',
|
||||
start: Object.assign({}, token.start),
|
||||
// Note: correct end is set later.
|
||||
end: Object.assign({}, token.end)
|
||||
};
|
||||
map.add(index, 0, [['enter', currentTable, context]]);
|
||||
} else if (token.type === 'tableRow' || token.type === 'tableDelimiterRow') {
|
||||
inFirstCellAwaitingPipe = true;
|
||||
currentCell = undefined;
|
||||
lastCell = [0, 0, 0, 0];
|
||||
cell = [0, index + 1, 0, 0];
|
||||
|
||||
// Inject table body start.
|
||||
if (afterHeadAwaitingFirstBodyRow) {
|
||||
afterHeadAwaitingFirstBodyRow = false;
|
||||
currentBody = {
|
||||
type: 'tableBody',
|
||||
start: Object.assign({}, token.start),
|
||||
// Note: correct end is set later.
|
||||
end: Object.assign({}, token.end)
|
||||
};
|
||||
map.add(index, 0, [['enter', currentBody, context]]);
|
||||
}
|
||||
rowKind = token.type === 'tableDelimiterRow' ? 2 : currentBody ? 3 : 1;
|
||||
}
|
||||
// Cell data.
|
||||
else if (rowKind && (token.type === "data" || token.type === 'tableDelimiterMarker' || token.type === 'tableDelimiterFiller')) {
|
||||
inFirstCellAwaitingPipe = false;
|
||||
|
||||
// First value in cell.
|
||||
if (cell[2] === 0) {
|
||||
if (lastCell[1] !== 0) {
|
||||
cell[0] = cell[1];
|
||||
currentCell = flushCell(map, context, lastCell, rowKind, undefined, currentCell);
|
||||
lastCell = [0, 0, 0, 0];
|
||||
}
|
||||
cell[2] = index;
|
||||
}
|
||||
} else if (token.type === 'tableCellDivider') {
|
||||
if (inFirstCellAwaitingPipe) {
|
||||
inFirstCellAwaitingPipe = false;
|
||||
} else {
|
||||
if (lastCell[1] !== 0) {
|
||||
cell[0] = cell[1];
|
||||
currentCell = flushCell(map, context, lastCell, rowKind, undefined, currentCell);
|
||||
}
|
||||
lastCell = cell;
|
||||
cell = [lastCell[1], index, 0, 0];
|
||||
}
|
||||
}
|
||||
}
|
||||
// Exit events.
|
||||
else if (token.type === 'tableHead') {
|
||||
afterHeadAwaitingFirstBodyRow = true;
|
||||
lastTableEnd = index;
|
||||
} else if (token.type === 'tableRow' || token.type === 'tableDelimiterRow') {
|
||||
lastTableEnd = index;
|
||||
if (lastCell[1] !== 0) {
|
||||
cell[0] = cell[1];
|
||||
currentCell = flushCell(map, context, lastCell, rowKind, index, currentCell);
|
||||
} else if (cell[1] !== 0) {
|
||||
currentCell = flushCell(map, context, cell, rowKind, index, currentCell);
|
||||
}
|
||||
rowKind = 0;
|
||||
} else if (rowKind && (token.type === "data" || token.type === 'tableDelimiterMarker' || token.type === 'tableDelimiterFiller')) {
|
||||
cell[3] = index;
|
||||
}
|
||||
}
|
||||
if (lastTableEnd !== 0) {
|
||||
flushTableEnd(map, context, lastTableEnd, currentTable, currentBody);
|
||||
}
|
||||
map.consume(context.events);
|
||||
|
||||
// To do: move this into `html`, when events are exposed there.
|
||||
// That’s what `markdown-rs` does.
|
||||
// That needs updates to `mdast-util-gfm-table`.
|
||||
index = -1;
|
||||
while (++index < context.events.length) {
|
||||
const event = context.events[index];
|
||||
if (event[0] === 'enter' && event[1].type === 'table') {
|
||||
event[1]._align = gfmTableAlign(context.events, index);
|
||||
}
|
||||
}
|
||||
return events;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a cell.
|
||||
*
|
||||
* @param {EditMap} map
|
||||
* @param {Readonly<TokenizeContext>} context
|
||||
* @param {Readonly<Range>} range
|
||||
* @param {RowKind} rowKind
|
||||
* @param {number | undefined} rowEnd
|
||||
* @param {Token | undefined} previousCell
|
||||
* @returns {Token | undefined}
|
||||
*/
|
||||
// eslint-disable-next-line max-params
|
||||
function flushCell(map, context, range, rowKind, rowEnd, previousCell) {
|
||||
// `markdown-rs` uses:
|
||||
// rowKind === 2 ? 'tableDelimiterCell' : 'tableCell'
|
||||
const groupName = rowKind === 1 ? 'tableHeader' : rowKind === 2 ? 'tableDelimiter' : 'tableData';
|
||||
// `markdown-rs` uses:
|
||||
// rowKind === 2 ? 'tableDelimiterCellValue' : 'tableCellText'
|
||||
const valueName = 'tableContent';
|
||||
|
||||
// Insert an exit for the previous cell, if there is one.
|
||||
//
|
||||
// ```markdown
|
||||
// > | | aa | bb | cc |
|
||||
// ^-- exit
|
||||
// ^^^^-- this cell
|
||||
// ```
|
||||
if (range[0] !== 0) {
|
||||
previousCell.end = Object.assign({}, getPoint(context.events, range[0]));
|
||||
map.add(range[0], 0, [['exit', previousCell, context]]);
|
||||
}
|
||||
|
||||
// Insert enter of this cell.
|
||||
//
|
||||
// ```markdown
|
||||
// > | | aa | bb | cc |
|
||||
// ^-- enter
|
||||
// ^^^^-- this cell
|
||||
// ```
|
||||
const now = getPoint(context.events, range[1]);
|
||||
previousCell = {
|
||||
type: groupName,
|
||||
start: Object.assign({}, now),
|
||||
// Note: correct end is set later.
|
||||
end: Object.assign({}, now)
|
||||
};
|
||||
map.add(range[1], 0, [['enter', previousCell, context]]);
|
||||
|
||||
// Insert text start at first data start and end at last data end, and
|
||||
// remove events between.
|
||||
//
|
||||
// ```markdown
|
||||
// > | | aa | bb | cc |
|
||||
// ^-- enter
|
||||
// ^-- exit
|
||||
// ^^^^-- this cell
|
||||
// ```
|
||||
if (range[2] !== 0) {
|
||||
const relatedStart = getPoint(context.events, range[2]);
|
||||
const relatedEnd = getPoint(context.events, range[3]);
|
||||
/** @type {Token} */
|
||||
const valueToken = {
|
||||
type: valueName,
|
||||
start: Object.assign({}, relatedStart),
|
||||
end: Object.assign({}, relatedEnd)
|
||||
};
|
||||
map.add(range[2], 0, [['enter', valueToken, context]]);
|
||||
if (rowKind !== 2) {
|
||||
// Fix positional info on remaining events
|
||||
const start = context.events[range[2]];
|
||||
const end = context.events[range[3]];
|
||||
start[1].end = Object.assign({}, end[1].end);
|
||||
start[1].type = "chunkText";
|
||||
start[1].contentType = "text";
|
||||
|
||||
// Remove if needed.
|
||||
if (range[3] > range[2] + 1) {
|
||||
const a = range[2] + 1;
|
||||
const b = range[3] - range[2] - 1;
|
||||
map.add(a, b, []);
|
||||
}
|
||||
}
|
||||
map.add(range[3] + 1, 0, [['exit', valueToken, context]]);
|
||||
}
|
||||
|
||||
// Insert an exit for the last cell, if at the row end.
|
||||
//
|
||||
// ```markdown
|
||||
// > | | aa | bb | cc |
|
||||
// ^-- exit
|
||||
// ^^^^^^-- this cell (the last one contains two “between” parts)
|
||||
// ```
|
||||
if (rowEnd !== undefined) {
|
||||
previousCell.end = Object.assign({}, getPoint(context.events, rowEnd));
|
||||
map.add(rowEnd, 0, [['exit', previousCell, context]]);
|
||||
previousCell = undefined;
|
||||
}
|
||||
return previousCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate table end (and table body end).
|
||||
*
|
||||
* @param {Readonly<EditMap>} map
|
||||
* @param {Readonly<TokenizeContext>} context
|
||||
* @param {number} index
|
||||
* @param {Token} table
|
||||
* @param {Token | undefined} tableBody
|
||||
*/
|
||||
// eslint-disable-next-line max-params
|
||||
function flushTableEnd(map, context, index, table, tableBody) {
|
||||
/** @type {Array<Event>} */
|
||||
const exits = [];
|
||||
const related = getPoint(context.events, index);
|
||||
if (tableBody) {
|
||||
tableBody.end = Object.assign({}, related);
|
||||
exits.push(['exit', tableBody, context]);
|
||||
}
|
||||
table.end = Object.assign({}, related);
|
||||
exits.push(['exit', table, context]);
|
||||
map.add(index + 1, 0, exits);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Readonly<Array<Event>>} events
|
||||
* @param {number} index
|
||||
* @returns {Readonly<Point>}
|
||||
*/
|
||||
function getPoint(events, index) {
|
||||
const event = events[index];
|
||||
const side = event[0] === 'enter' ? 'start' : 'end';
|
||||
return event[1][side];
|
||||
}
|
22
node_modules/micromark-extension-gfm-table/license
generated
vendored
Normal file
22
node_modules/micromark-extension-gfm-table/license
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
(The MIT License)
|
||||
|
||||
Copyright (c) Titus Wormer <tituswormer@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
'Software'), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
128
node_modules/micromark-extension-gfm-table/package.json
generated
vendored
Normal file
128
node_modules/micromark-extension-gfm-table/package.json
generated
vendored
Normal file
@@ -0,0 +1,128 @@
|
||||
{
|
||||
"author": "Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)",
|
||||
"bugs": "https://github.com/micromark/micromark-extension-gfm-table/issues",
|
||||
"contributors": [
|
||||
"Titus Wormer <tituswormer@gmail.com> (https://wooorm.com)"
|
||||
],
|
||||
"dependencies": {
|
||||
"devlop": "^1.0.0",
|
||||
"micromark-factory-space": "^2.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"description": "micromark extension to support GFM tables",
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.0.0",
|
||||
"c8": "^10.0.0",
|
||||
"create-gfm-fixtures": "^2.0.0",
|
||||
"micromark": "^4.0.0",
|
||||
"micromark-build": "^2.0.0",
|
||||
"prettier": "^3.0.0",
|
||||
"remark-cli": "^12.0.0",
|
||||
"remark-preset-wooorm": "^10.0.0",
|
||||
"type-coverage": "^2.0.0",
|
||||
"typescript": "^5.0.0",
|
||||
"xo": "^0.60.0"
|
||||
},
|
||||
"exports": {
|
||||
"development": "./dev/index.js",
|
||||
"default": "./index.js"
|
||||
},
|
||||
"files": [
|
||||
"dev/",
|
||||
"index.d.ts",
|
||||
"index.js",
|
||||
"lib/"
|
||||
],
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
},
|
||||
"keywords": [
|
||||
"cell",
|
||||
"column",
|
||||
"gfm",
|
||||
"markdown",
|
||||
"micromark-extension",
|
||||
"micromark",
|
||||
"row",
|
||||
"table",
|
||||
"tabular",
|
||||
"unified"
|
||||
],
|
||||
"license": "MIT",
|
||||
"name": "micromark-extension-gfm-table",
|
||||
"prettier": {
|
||||
"bracketSpacing": false,
|
||||
"semi": false,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "none",
|
||||
"useTabs": false
|
||||
},
|
||||
"remarkConfig": {
|
||||
"plugins": [
|
||||
"remark-preset-wooorm"
|
||||
]
|
||||
},
|
||||
"repository": "micromark/micromark-extension-gfm-table",
|
||||
"scripts": {
|
||||
"build": "tsc --build --clean && tsc --build && type-coverage && micromark-build",
|
||||
"format": "remark --frail --quiet --output -- . && prettier --log-level warn --write -- . && xo --fix",
|
||||
"test-api-dev": "node --conditions development test/index.js",
|
||||
"test-api-prod": "node --conditions production test/index.js",
|
||||
"test-api": "npm run test-api-dev && npm run test-api-prod",
|
||||
"test-coverage": "c8 --100 --reporter lcov -- npm run test-api",
|
||||
"test": "npm run build && npm run format && npm run test-coverage"
|
||||
},
|
||||
"sideEffects": false,
|
||||
"typeCoverage": {
|
||||
"atLeast": 100,
|
||||
"strict": true
|
||||
},
|
||||
"type": "module",
|
||||
"version": "2.1.1",
|
||||
"xo": {
|
||||
"overrides": [
|
||||
{
|
||||
"files": [
|
||||
"**/*.d.ts"
|
||||
],
|
||||
"rules": {
|
||||
"@typescript-eslint/array-type": [
|
||||
"error",
|
||||
{
|
||||
"default": "generic"
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/ban-types": [
|
||||
"error",
|
||||
{
|
||||
"extendDefaults": true
|
||||
}
|
||||
],
|
||||
"@typescript-eslint/consistent-type-definitions": [
|
||||
"error",
|
||||
"interface"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"files": [
|
||||
"test/**/*.js"
|
||||
],
|
||||
"rules": {
|
||||
"no-await-in-loop": "off"
|
||||
}
|
||||
}
|
||||
],
|
||||
"prettier": true,
|
||||
"rules": {
|
||||
"complexity": "off",
|
||||
"max-depth": "off",
|
||||
"unicorn/no-this-assignment": "off",
|
||||
"unicorn/prefer-string-replace-all": "off"
|
||||
}
|
||||
}
|
||||
}
|
515
node_modules/micromark-extension-gfm-table/readme.md
generated
vendored
Normal file
515
node_modules/micromark-extension-gfm-table/readme.md
generated
vendored
Normal file
@@ -0,0 +1,515 @@
|
||||
# micromark-extension-gfm-table
|
||||
|
||||
[![Build][build-badge]][build]
|
||||
[![Coverage][coverage-badge]][coverage]
|
||||
[![Downloads][downloads-badge]][downloads]
|
||||
[![Size][size-badge]][size]
|
||||
[![Sponsors][sponsors-badge]][collective]
|
||||
[![Backers][backers-badge]][collective]
|
||||
[![Chat][chat-badge]][chat]
|
||||
|
||||
[micromark][] extensions to support GFM [tables][].
|
||||
|
||||
## Contents
|
||||
|
||||
* [What is this?](#what-is-this)
|
||||
* [When to use this](#when-to-use-this)
|
||||
* [Install](#install)
|
||||
* [Use](#use)
|
||||
* [API](#api)
|
||||
* [`gfmTable()`](#gfmtable)
|
||||
* [`gfmTableHtml()`](#gfmtablehtml)
|
||||
* [Bugs](#bugs)
|
||||
* [Authoring](#authoring)
|
||||
* [HTML](#html)
|
||||
* [CSS](#css)
|
||||
* [Syntax](#syntax)
|
||||
* [Types](#types)
|
||||
* [Compatibility](#compatibility)
|
||||
* [Security](#security)
|
||||
* [Related](#related)
|
||||
* [Contribute](#contribute)
|
||||
* [License](#license)
|
||||
|
||||
## What is this?
|
||||
|
||||
This package contains extensions that add support for the table syntax enabled
|
||||
by GFM to [`micromark`][micromark].
|
||||
These extensions match github.com.
|
||||
|
||||
## When to use this
|
||||
|
||||
This project is useful when you want to support tables in markdown.
|
||||
|
||||
You can use these extensions when you are working with [`micromark`][micromark].
|
||||
To support all GFM features, use
|
||||
[`micromark-extension-gfm`][micromark-extension-gfm] instead.
|
||||
|
||||
When you need a syntax tree, combine this package with
|
||||
[`mdast-util-gfm-table`][mdast-util-gfm-table].
|
||||
|
||||
All these packages are used in [`remark-gfm`][remark-gfm], which focusses on
|
||||
making it easier to transform content by abstracting these internals away.
|
||||
|
||||
## Install
|
||||
|
||||
This package is [ESM only][esm].
|
||||
In Node.js (version 16+), install with [npm][]:
|
||||
|
||||
```sh
|
||||
npm install micromark-extension-gfm-table
|
||||
```
|
||||
|
||||
In Deno with [`esm.sh`][esmsh]:
|
||||
|
||||
```js
|
||||
import {gfmTable, gfmTableHtml} from 'https://esm.sh/micromark-extension-gfm-table@2'
|
||||
```
|
||||
|
||||
In browsers with [`esm.sh`][esmsh]:
|
||||
|
||||
```html
|
||||
<script type="module">
|
||||
import {gfmTable, gfmTableHtml} from 'https://esm.sh/micromark-extension-gfm-table@2?bundle'
|
||||
</script>
|
||||
```
|
||||
|
||||
## Use
|
||||
|
||||
```js
|
||||
import {micromark} from 'micromark'
|
||||
import {gfmTable, gfmTableHtml} from 'micromark-extension-gfm-table'
|
||||
|
||||
const output = micromark('| a |\n| - |', {
|
||||
extensions: [gfmTable()],
|
||||
htmlExtensions: [gfmTableHtml()]
|
||||
})
|
||||
|
||||
console.log(output)
|
||||
```
|
||||
|
||||
Yields:
|
||||
|
||||
```html
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
</tr>
|
||||
</thead>
|
||||
</table>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
This package exports the identifiers [`gfmTable`][api-gfm-table] and
|
||||
[`gfmTableHtml`][api-gfm-table-html].
|
||||
There is no default export.
|
||||
|
||||
The export map supports the [`development` condition][development].
|
||||
Run `node --conditions development module.js` to get instrumented dev code.
|
||||
Without this condition, production code is loaded.
|
||||
|
||||
### `gfmTable()`
|
||||
|
||||
Create an HTML extension for `micromark` to support GitHub tables syntax.
|
||||
|
||||
###### Returns
|
||||
|
||||
Extension for `micromark` that can be passed in `extensions` to enable GFM
|
||||
table syntax ([`Extension`][micromark-extension]).
|
||||
|
||||
### `gfmTableHtml()`
|
||||
|
||||
Create an HTML extension for `micromark` to support GitHub tables when
|
||||
serializing to HTML.
|
||||
|
||||
###### Returns
|
||||
|
||||
Extension for `micromark` that can be passed in `htmlExtensions` to support
|
||||
GFM tables when serializing to HTML
|
||||
([`HtmlExtension`][micromark-html-extension]).
|
||||
|
||||
## Bugs
|
||||
|
||||
GitHub’s own algorithm to parse tables contains a bug.
|
||||
This bug is not present in this project.
|
||||
The issue relating to tables is:
|
||||
|
||||
* [GFM tables: escaped escapes are incorrectly treated as
|
||||
escapes](https://github.com/github/cmark-gfm/issues/277)
|
||||
|
||||
## Authoring
|
||||
|
||||
When authoring markdown with GFM tables, it’s recommended to *always* put
|
||||
pipes around cells.
|
||||
Without them, it can be hard to infer whether the table will work, how many
|
||||
columns there are, and which column you are currently editing.
|
||||
|
||||
It is recommended to not use many columns, as it results in very long lines,
|
||||
making it hard to infer which column you are currently editing.
|
||||
|
||||
For larger tables, particularly when cells vary in size, it is recommended
|
||||
*not* to manually “pad” cell text.
|
||||
While it can look better, it results in a lot of time spent realigning
|
||||
everything when a new, longer cell is added or the longest cell removed, as
|
||||
every row then must be changed.
|
||||
Other than costing time, it also causes large diffs in Git.
|
||||
|
||||
To illustrate, when authoring large tables, it is discouraged to pad cells
|
||||
like this:
|
||||
|
||||
```markdown
|
||||
| Alpha bravo charlie | delta |
|
||||
| ------------------- | -----------------: |
|
||||
| Echo | Foxtrot golf hotel |
|
||||
```
|
||||
|
||||
Instead, use single spaces (and single filler dashes):
|
||||
|
||||
```markdown
|
||||
| Alpha bravo charlie | delta |
|
||||
| - | -: |
|
||||
| Echo | Foxtrot golf hotel |
|
||||
```
|
||||
|
||||
## HTML
|
||||
|
||||
GFM tables relate to several HTML elements: `<table>`, `<tbody>`, `<td>`,
|
||||
`<th>`, `<thead>`, and `<tr>`.
|
||||
See
|
||||
[*§ 4.9.1 The `table` element*][html-table],
|
||||
[*§ 4.9.5 The `tbody` element*][html-tbody],
|
||||
[*§ 4.9.9 The `td` element*][html-td],
|
||||
[*§ 4.9.10 The `th` element*][html-th],
|
||||
[*§ 4.9.6 The `thead` element*][html-thead], and
|
||||
[*§ 4.9.8 The `tr` element*][html-tr]
|
||||
in the HTML spec for more info.
|
||||
|
||||
If the alignment of a column is left, right, or center, a deprecated
|
||||
`align` attribute is added to each `<th>` and `<td>` element belonging to
|
||||
that column.
|
||||
That attribute is interpreted by browsers as if a CSS `text-align` property
|
||||
was included, with its value set to that same keyword.
|
||||
|
||||
## CSS
|
||||
|
||||
The following CSS is needed to make tables look a bit like GitHub.
|
||||
For the complete actual CSS see
|
||||
[`sindresorhus/github-markdown-css`][github-markdown-css]
|
||||
|
||||
```css
|
||||
/* Light theme. */
|
||||
:root {
|
||||
--color-canvas-default: #ffffff;
|
||||
--color-canvas-subtle: #f6f8fa;
|
||||
--color-border-default: #d0d7de;
|
||||
--color-border-muted: hsla(210, 18%, 87%, 1);
|
||||
}
|
||||
|
||||
/* Dark theme. */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--color-canvas-default: #0d1117;
|
||||
--color-canvas-subtle: #161b22;
|
||||
--color-border-default: #30363d;
|
||||
--color-border-muted: #21262d;
|
||||
}
|
||||
}
|
||||
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
display: block;
|
||||
margin-top: 0;
|
||||
margin-bottom: 16px;
|
||||
width: max-content;
|
||||
max-width: 100%;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
tr {
|
||||
background-color: var(--color-canvas-default);
|
||||
border-top: 1px solid var(--color-border-muted);
|
||||
}
|
||||
|
||||
tr:nth-child(2n) {
|
||||
background-color: var(--color-canvas-subtle);
|
||||
}
|
||||
|
||||
td,
|
||||
th {
|
||||
padding: 6px 13px;
|
||||
border: 1px solid var(--color-border-default);
|
||||
}
|
||||
|
||||
th {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
table img {
|
||||
background-color: transparent;
|
||||
}
|
||||
```
|
||||
|
||||
## Syntax
|
||||
|
||||
Tables form with the following BNF:
|
||||
|
||||
```abnf
|
||||
gfmTable ::= gfmTableHead 0*(eol gfmTableBodyRow)
|
||||
|
||||
; Restriction: both rows must have the same number of cells.
|
||||
gfmTableHead ::= gfmTableRow eol gfmTableDelimiterRow
|
||||
|
||||
gfmTableRow ::= ["|"] gfmTableCell 0*("|" gfmTableCell) ["|"] *spaceOrTab
|
||||
gfmTableCell ::= *spaceOrTab gfmTableText *spaceOrTab
|
||||
gfmTableText ::= 0*(line - "\\" - "|" / "\\" ["\\" / "|"])
|
||||
|
||||
gfmTableDelimiterRow ::= ["|"] gfmTableDelimiterCell 0*("|" gfmTableDelimiterCell) ["|"] *spaceOrTab
|
||||
gfmTableDelimiterCell ::= *spaceOrTab gfmTableDelimiterValue *spaceOrTab
|
||||
gfmTableDelimiterValue ::= [":"] 1*"-" [":"]
|
||||
```
|
||||
|
||||
As this construct occurs in flow, like all flow constructs, it must be
|
||||
followed by an eol (line ending) or eof (end of file).
|
||||
|
||||
The above grammar shows that basically anything can be a cell or a row.
|
||||
The main thing that makes something a row, is that it occurs directly before
|
||||
or after a delimiter row, or after another row.
|
||||
|
||||
It is not required for a table to have a body: it can end right after the
|
||||
delimiter row.
|
||||
|
||||
Each column can be marked with an alignment.
|
||||
The alignment marker is a colon (`:`) used before and/or after delimiter row
|
||||
filler.
|
||||
To illustrate:
|
||||
|
||||
```markdown
|
||||
| none | left | right | center |
|
||||
| ---- | :--- | ----: | :----: |
|
||||
```
|
||||
|
||||
The number of cells in the delimiter row, is the number of columns of the
|
||||
table.
|
||||
Only the head row is required to have the same number of cells.
|
||||
Body rows are not required to have a certain number of cells.
|
||||
For body rows that have less cells than the number of columns of the table,
|
||||
empty cells are injected.
|
||||
When a row has more cells than the number of columns of the table, the
|
||||
superfluous cells are dropped.
|
||||
To illustrate:
|
||||
|
||||
```markdown
|
||||
| a | b |
|
||||
| - | - |
|
||||
| c |
|
||||
| d | e | f |
|
||||
```
|
||||
|
||||
Yields:
|
||||
|
||||
```html
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>a</th>
|
||||
<th>b</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>c</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>d</td>
|
||||
<td>e</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
```
|
||||
|
||||
Each cell’s text is interpreted as the [text][micromark-content-type] content
|
||||
type.
|
||||
That means that it can include constructs such as attention (emphasis, strong).
|
||||
|
||||
The grammar for cells prohibits the use of `|` in them.
|
||||
To use pipes in cells, encode them as a character reference or character
|
||||
escape: `|` (or `|`, `|`, `|`, `|`) or
|
||||
`\|`.
|
||||
|
||||
Escapes will typically work, but they are not supported in
|
||||
code (text) (and the math (text) extension).
|
||||
To work around this, GitHub came up with a rather weird “trick”.
|
||||
When inside a table cell *and* inside code, escaped pipes *are* decoded.
|
||||
To illustrate:
|
||||
|
||||
```markdown
|
||||
| Name | Character |
|
||||
| - | - |
|
||||
| Left curly brace | `{` |
|
||||
| Pipe | `\|` |
|
||||
| Right curly brace | `}` |
|
||||
```
|
||||
|
||||
Yields:
|
||||
|
||||
```html
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Character</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Left curly brace</td>
|
||||
<td><code>{</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Pipe</td>
|
||||
<td><code>|</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Right curly brace</td>
|
||||
<td><code>}</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
```
|
||||
|
||||
> 👉 **Note**: no other character can be escaped like this.
|
||||
> Escaping pipes in code does not work when not inside a table, either.
|
||||
|
||||
## Types
|
||||
|
||||
This package is fully typed with [TypeScript][].
|
||||
It exports no additional types.
|
||||
|
||||
## Compatibility
|
||||
|
||||
Projects maintained by the unified collective are compatible with maintained
|
||||
versions of Node.js.
|
||||
|
||||
When we cut a new major release, we drop support for unmaintained versions of
|
||||
Node.
|
||||
This means we try to keep the current release line,
|
||||
`micromark-extension-gfm-table@^2`, compatible with Node.js 16.
|
||||
|
||||
This package works with `micromark` version `3` and later.
|
||||
|
||||
## Security
|
||||
|
||||
This package is safe.
|
||||
|
||||
## Related
|
||||
|
||||
* [`micromark-extension-gfm`][micromark-extension-gfm]
|
||||
— support all of GFM
|
||||
* [`mdast-util-gfm-table`][mdast-util-gfm-table]
|
||||
— support all of GFM in mdast
|
||||
* [`mdast-util-gfm`][mdast-util-gfm]
|
||||
— support all of GFM in mdast
|
||||
* [`remark-gfm`][remark-gfm]
|
||||
— support all of GFM in remark
|
||||
|
||||
## Contribute
|
||||
|
||||
See [`contributing.md` in `micromark/.github`][contributing] for ways to get
|
||||
started.
|
||||
See [`support.md`][support] for ways to get help.
|
||||
|
||||
This project has a [code of conduct][coc].
|
||||
By interacting with this repository, organization, or community you agree to
|
||||
abide by its terms.
|
||||
|
||||
## License
|
||||
|
||||
[MIT][license] © [Titus Wormer][author]
|
||||
|
||||
<!-- Definitions -->
|
||||
|
||||
[build-badge]: https://github.com/micromark/micromark-extension-gfm-table/workflows/main/badge.svg
|
||||
|
||||
[build]: https://github.com/micromark/micromark-extension-gfm-table/actions
|
||||
|
||||
[coverage-badge]: https://img.shields.io/codecov/c/github/micromark/micromark-extension-gfm-table.svg
|
||||
|
||||
[coverage]: https://codecov.io/github/micromark/micromark-extension-gfm-table
|
||||
|
||||
[downloads-badge]: https://img.shields.io/npm/dm/micromark-extension-gfm-table.svg
|
||||
|
||||
[downloads]: https://www.npmjs.com/package/micromark-extension-gfm-table
|
||||
|
||||
[size-badge]: https://img.shields.io/badge/dynamic/json?label=minzipped%20size&query=$.size.compressedSize&url=https://deno.bundlejs.com/?q=micromark-extension-gfm-table
|
||||
|
||||
[size]: https://bundlejs.com/?q=micromark-extension-gfm-table
|
||||
|
||||
[sponsors-badge]: https://opencollective.com/unified/sponsors/badge.svg
|
||||
|
||||
[backers-badge]: https://opencollective.com/unified/backers/badge.svg
|
||||
|
||||
[collective]: https://opencollective.com/unified
|
||||
|
||||
[chat-badge]: https://img.shields.io/badge/chat-discussions-success.svg
|
||||
|
||||
[chat]: https://github.com/micromark/micromark/discussions
|
||||
|
||||
[npm]: https://docs.npmjs.com/cli/install
|
||||
|
||||
[esmsh]: https://esm.sh
|
||||
|
||||
[license]: license
|
||||
|
||||
[author]: https://wooorm.com
|
||||
|
||||
[contributing]: https://github.com/micromark/.github/blob/main/contributing.md
|
||||
|
||||
[support]: https://github.com/micromark/.github/blob/main/support.md
|
||||
|
||||
[coc]: https://github.com/micromark/.github/blob/main/code-of-conduct.md
|
||||
|
||||
[esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c
|
||||
|
||||
[typescript]: https://www.typescriptlang.org
|
||||
|
||||
[development]: https://nodejs.org/api/packages.html#packages_resolving_user_conditions
|
||||
|
||||
[micromark]: https://github.com/micromark/micromark
|
||||
|
||||
[micromark-extension]: https://github.com/micromark/micromark#syntaxextension
|
||||
|
||||
[micromark-html-extension]: https://github.com/micromark/micromark#htmlextension
|
||||
|
||||
[micromark-content-type]: https://github.com/micromark/micromark#content-types
|
||||
|
||||
[micromark-extension-gfm]: https://github.com/micromark/micromark-extension-gfm
|
||||
|
||||
[mdast-util-gfm]: https://github.com/syntax-tree/mdast-util-gfm
|
||||
|
||||
[mdast-util-gfm-table]: https://github.com/syntax-tree/mdast-util-gfm-table
|
||||
|
||||
[remark-gfm]: https://github.com/remarkjs/remark-gfm
|
||||
|
||||
[tables]: https://github.github.com/gfm/#tables-extension-
|
||||
|
||||
[html-table]: https://html.spec.whatwg.org/multipage/tables.html#the-table-element
|
||||
|
||||
[html-tbody]: https://html.spec.whatwg.org/multipage/tables.html#the-tbody-element
|
||||
|
||||
[html-thead]: https://html.spec.whatwg.org/multipage/tables.html#the-thead-element
|
||||
|
||||
[html-tr]: https://html.spec.whatwg.org/multipage/tables.html#the-tr-element
|
||||
|
||||
[html-td]: https://html.spec.whatwg.org/multipage/tables.html#the-td-element
|
||||
|
||||
[html-th]: https://html.spec.whatwg.org/multipage/tables.html#the-th-element
|
||||
|
||||
[github-markdown-css]: https://github.com/sindresorhus/github-markdown-css
|
||||
|
||||
[api-gfm-table]: #gfmtable
|
||||
|
||||
[api-gfm-table-html]: #gfmtablehtml
|
Reference in New Issue
Block a user