Skip to content

Commit

Permalink
Merge pull request #7619 from weseek/imprv/gfm-table-performance
Browse files Browse the repository at this point in the history
imprv: GFM table performance
  • Loading branch information
yuki-takei committed May 6, 2023
2 parents 941c546 + e68969b commit b8e0260
Show file tree
Hide file tree
Showing 30 changed files with 3,052 additions and 14 deletions.
3 changes: 2 additions & 1 deletion apps/app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@
"@google-cloud/storage": "^5.8.5",
"@growi/core": "^6.1.0-RC.0",
"@growi/hackmd": "^6.1.0-RC.0",
"@growi/remark-attachment-refs": "^6.1.0-RC.0",
"@growi/preset-themes": "^6.1.0-RC.0",
"@growi/remark-attachment-refs": "^6.1.0-RC.0",
"@growi/remark-drawio": "^6.1.0-RC.0",
"@growi/remark-growi-directive": "^6.1.0-RC.0",
"@growi/remark-lsx": "^6.1.0-RC.0",
Expand Down Expand Up @@ -120,6 +120,7 @@
"markdown-table": "^1.1.1",
"md5": "^2.2.1",
"method-override": "^3.0.0",
"micromark-extension-gfm-table": "link:./packages/micromark-extension-gfm-table",
"migrate-mongo": "^8.2.3",
"mkdirp": "^1.0.3",
"mongoose": "^6.0.13",
Expand Down
1 change: 1 addition & 0 deletions packages/micromark-extension-gfm-table/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*.d.ts
5 changes: 5 additions & 0 deletions packages/micromark-extension-gfm-table/.eslintrc.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module.exports = {
rules: {
'@typescript-eslint/no-use-before-define': 'off',
},
};
3 changes: 3 additions & 0 deletions packages/micromark-extension-gfm-table/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
*.d.ts
/lib/
/index.js
3 changes: 3 additions & 0 deletions packages/micromark-extension-gfm-table/.prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
coverage/
*.html
*.md
1 change: 1 addition & 0 deletions packages/micromark-extension-gfm-table/.remarkignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test/
2 changes: 2 additions & 0 deletions packages/micromark-extension-gfm-table/dev/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export {gfmTableHtml} from './lib/html.js'
export {gfmTable} from './lib/syntax.js'
144 changes: 144 additions & 0 deletions packages/micromark-extension-gfm-table/dev/lib/html.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
/**
* @typedef {import('micromark-util-types').HtmlExtension} HtmlExtension
* @typedef {import('./syntax.js').Align} Align
*/

const alignment = {
none: '',
left: ' align="left"',
right: ' align="right"',
center: ' align="center"'
}

/**
* HTML extension for micromark (passed in `htmlExtensions`).
*
* @type {HtmlExtension}
*/
export const gfmTableHtml = {
enter: {
table(token) {
/** @type {Array<Align>} */
// @ts-expect-error Custom.
const tableAlign = token._align
this.lineEndingIfNeeded()
this.tag('<table>')
this.setData('tableAlign', tableAlign)
},
tableBody() {
// Clear slurping line ending from the delimiter row.
this.setData('slurpOneLineEnding')
this.tag('<tbody>')
},
tableData() {
const tableAlign = /** @type {Array<Align>} */ (
this.getData('tableAlign')
)
const tableColumn = /** @type {number} */ (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 = /** @type {Array<Align>} */ (
this.getData('tableAlign')
)
const tableColumn = /** @type {number} */ (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')
// If there was no table body, make sure the slurping from the delimiter row
// is cleared.
this.setData('slurpAllLineEndings')
this.lineEndingIfNeeded()
this.tag('</table>')
},
tableBody() {
this.lineEndingIfNeeded()
this.tag('</tbody>')
},
tableData() {
const tableAlign = /** @type {Array<Align>} */ (
this.getData('tableAlign')
)
const tableColumn = /** @type {number} */ (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>')
this.setData('slurpOneLineEnding', true)
// Slurp the line ending from the delimiter row.
},
tableHeader() {
const tableColumn = /** @type {number} */ (this.getData('tableColumn'))
this.tag('</th>')
this.setData('tableColumn', tableColumn + 1)
},
tableRow() {
const tableAlign = /** @type {Array<Align>} */ (
this.getData('tableAlign')
)
let tableColumn = /** @type {number} */ (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
}

0 comments on commit b8e0260

Please sign in to comment.