Skip to content

Commit 304192b

Browse files
perf: pre-declare position on table factories
Problem: the table handlers build table, tableRow, and tableCell nodes as fresh literals, then mdast-util-from-markdown's enter() sets node.position afterwards. V8 treats the late assignment as a shape change, so each node walks through two hidden classes instead of one. Core nodes already avoid this by declaring position up front; extension nodes leave the tree with mixed layouts. Goal: declare position on all three factory literals at construction so V8 keeps a single hidden class per node type. Changes: - lib/index.js: trailing position: undefined on the table literal in enterTable. - lib/index.js: trailing position: undefined on the tableRow literal in enterRow. - lib/index.js: trailing position: undefined on the tableCell literal in enterCell. Notes: pairs with the matching core change in syntax-tree/mdast-util-from-markdown#53; merged on its own this branch is a no-op. Validated with npm test (build, format, 100% coverage, 32 of 32 tests in dev and prod). The branch also includes a small chore commit at lib/index.js:233 through 237 that drops three @ts-expect-error directives that no longer match the current markdown-table types and that fail tsc on upstream main as written. Without that cleanup the package's own test script does not pass, so the chore commit is required to land before this one. Squash or split per maintainer preference. Bench (local harness, 3-run median-of-medians, GFM tokenizer and mdast extensions stacked). Numbers below are the parse time delta versus an unmodified upstream main; positive numbers mean slower, negative numbers mean faster. Inputs: a 4-column 1000-row table and a 20-column 100-row table. Tables sit at low mdast-layer ratios on the baseline (1.08 and 1.09 respectively); the bottleneck for tables is in micromark-extension-gfm-table, not in this util. Numbers should be read as "no regression" rather than "credible win." Effect of pairing this branch with PR #53: - 4 cols x 1000 rows: PR #53 alone: 4.7 percent slower. PR #53 with this branch alongside: 6.2 percent slower. - 20 cols x 100 rows: PR #53 alone: 5.0 percent slower. PR #53 with this branch alongside: 7.2 percent slower. Both rows sit inside the machine's drift band of 4 to 12 percent (main vs main with no code change in the same window). Pairing neither helps nor hurts table parses meaningfully, which matches what the baseline ratio predicts. The branch is included for shape consistency across the GFM stack rather than for a measurable per-table win.
1 parent 187d4d3 commit 304192b

1 file changed

Lines changed: 9 additions & 3 deletions

File tree

lib/index.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,13 +65,17 @@ export function gfmTableFromMarkdown() {
6565
function enterTable(token) {
6666
const align = token._align
6767
assert(align, 'expected `_align` on table')
68+
// Trailing `position: undefined` keeps the table hidden class stable;
69+
// mdast-util-from-markdown's enter() patches the field to a real value
70+
// but the property already exists, so no shape transition fires.
6871
this.enter(
6972
{
7073
type: 'table',
7174
align: align.map(function (d) {
7275
return d === 'none' ? null : d
7376
}),
74-
children: []
77+
children: [],
78+
position: undefined
7579
},
7680
token
7781
)
@@ -92,7 +96,8 @@ function exitTable(token) {
9296
* @type {FromMarkdownHandle}
9397
*/
9498
function enterRow(token) {
95-
this.enter({type: 'tableRow', children: []}, token)
99+
// See enterTable above for the rationale on the trailing position field.
100+
this.enter({type: 'tableRow', children: [], position: undefined}, token)
96101
}
97102

98103
/**
@@ -108,7 +113,8 @@ function exit(token) {
108113
* @type {FromMarkdownHandle}
109114
*/
110115
function enterCell(token) {
111-
this.enter({type: 'tableCell', children: []}, token)
116+
// See enterTable above for the rationale on the trailing position field.
117+
this.enter({type: 'tableCell', children: [], position: undefined}, token)
112118
}
113119

114120
// Overwrite the default code text data handler to unescape escaped pipes when

0 commit comments

Comments
 (0)