-
-
Notifications
You must be signed in to change notification settings - Fork 415
Description
Description
While working with the local build pipeline, I discovered a bug in the custom remark plugins that can cause the entire build process to crash with an unhandled TypeError.
The issue stems from how heading IDs are tracked in remark/remark-headings.js. Currently, they are stored in a standard JavaScript object:
file.data.headings = {};
Later, in remark/remark-reference-links.js, the code checks for the existence of an ID using the in operator:
if (!(id in file.data.headings)) {
throw Error(`ReferenceLinkError: No header found with id "${id}"`);
}Because file.data.headings is a plain object, it implicitly inherits properties from Object.prototype (like constructor, toString, or __proto__). If a document contains a heading or a reference that normalizes to one of these built-in property names (for example, a heading titled "Constructor"), the in check erroneously returns true.
Instead of throwing the intended ReferenceLinkError, the plugin attempts to treat the native function (e.g., Object.prototype.constructor) as an AST node, leading to a fatal crash downstream:
TypeError: Cannot read properties of undefined (reading 'section')
Why this matters
This is a critical Developer Experience (DX) issue. In technical specifications, terms like "Constructor" or "Prototype" are extremely common as headings. If an author refers to one of these via a reference link (e.g., {{constructor}}), the CI build will fail with an obscure error message that provides no hint to the author about what went wrong in their markdown.
Steps to Reproduce
- Create a markdown file with a heading named
constructor:# constructor Reference: {{constructor}} - Run the build command:
npm run build - The build will crash with
TypeError: Cannot read properties of undefined (reading 'section').