Skip to content

fix(metadata): reset lastIndex of unix manual page regex before testing - #947

Open
btea wants to merge 1 commit into
nodejs:mainfrom
btea:fix/unix-manual-regex-lastindex
Open

fix(metadata): reset lastIndex of unix manual page regex before testing#947
btea wants to merge 1 commit into
nodejs:mainfrom
btea:fix/unix-manual-regex-lastindex

Conversation

@btea

@btea btea commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

QUERIES.unixManualPage is a global regex (/g), so its lastIndex persists between calls. UNIST.isTextWithUnixManual uses .test() on this shared instance while visiting text nodes: after a successful match, the next .test() starts from the end of the previous match, intermittently returning false for text that does contain a Unix manual page reference.

This resets lastIndex to 0 before each test so every node is matched from the start.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test#:~:text=They%20store%20a%20lastIndex%20from%20the%20previous%20match.%20Using%20this%20internally%2C%20test()%20can%20be%20used%20to%20iterate%20over%20multiple%20matches%20in%20a%20string%20of%20text%20(with%20capture%20groups).

Copilot AI review requested due to automatic review settings July 27, 2026 13:28
@btea
btea requested a review from a team as a code owner July 27, 2026 13:28
@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
api-docs-tooling Ready Ready Preview Jul 27, 2026 1:29pm

Request Review

@vercel

vercel Bot commented Jul 27, 2026

Copy link
Copy Markdown

@btea is attempting to deploy a commit to the OpenJS Foundation Team on Vercel.

A member of the Team first needs to authorize it.

@cursor

cursor Bot commented Jul 27, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Single-line behavioral fix in a query helper with no auth, data, or API surface changes.

Overview
Fixes intermittent false negatives when detecting Unix manual references (e.g. foo(1)) in MDAST text nodes during metadata parsing.

QUERIES.unixManualPage is a shared global regex (/g). UNIST.isTextWithUnixManual now sets lastIndex to 0 before each .test() so traversal does not inherit the previous match position. A patch changeset is included for @node-core/doc-kit.

Reviewed by Cursor Bugbot for commit 96d492e. Bugbot is set up for automated code reviews on this repo. Configure here.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@codecov

codecov Bot commented Jul 27, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 86.21%. Comparing base (cef45ca) to head (96d492e).

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #947   +/-   ##
=======================================
  Coverage   86.21%   86.21%           
=======================================
  Files         195      195           
  Lines       17690    17692    +2     
  Branches     1609     1609           
=======================================
+ Hits        15251    15253    +2     
  Misses       2433     2433           
  Partials        6        6           

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Comment on lines +44 to +47
isTextWithUnixManual: ({ type, value }) => {
QUERIES.unixManualPage.lastIndex = 0; // Reset the lastIndex to ensure proper matching
return type === 'text' && QUERIES.unixManualPage.test(value);
},

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you give an example of something it would miss?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I dug into this, and honestly: with the current call chain, nothing is observably missed today. isTextWithUnixManual is only used as a visit() predicate (src/generators/metadata/utils/parse.mjs:142), and every successful .test() is immediately followed by the visitor's node.value.replace(QUERIES.unixManualPage, ...) (src/generators/metadata/utils/visitors.mjs:33, same regex instance)

RegExp.prototype[@@replace], step 9, on a global regex resets lastIndex to 0. A failing .test() also resets it, so lastIndex is always 0 at the start of each test. Verified empirically: pre-fix vs post-fix predicates over all of node/doc/api/*.md produce identical matches.

So this is hardening against shared mutable regex state, not a fix for a currently visible bug. Happy to add a small unit test calling the predicate twice to lock it in, or close if you'd rather not carry the extra line.

@avivkeller

Copy link
Copy Markdown
Member

@btea is attempting to deploy a commit to the OpenJS Foundation Team on Vercel.

A member of the Team first needs to authorize it.

@nodejs/web-admins this shouldn't happen, we only want builds on api-docs-tooling

@MattIPv4

Copy link
Copy Markdown
Member

@btea is attempting to deploy a commit to the OpenJS Foundation Team on Vercel.
A member of the Team first needs to authorize it.

@nodejs/web-admins this shouldn't happen, we only want builds on api-docs-tooling

The ignore step was already set to production only, I've now disabled the "Pull Request Comments" Git functionality, will see if that helps.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants