Skip to content

refactor(mdxish): use variable name for heading slug generation#1340

Merged
eaglethrost merged 32 commits intonextfrom
dimas/CX-2929-mdxish-heading-stabilize-slug-generation
Feb 20, 2026
Merged

refactor(mdxish): use variable name for heading slug generation#1340
eaglethrost merged 32 commits intonextfrom
dimas/CX-2929-mdxish-heading-stabilize-slug-generation

Conversation

@eaglethrost
Copy link
Copy Markdown
Contributor

@eaglethrost eaglethrost commented Feb 13, 2026

PR App Fix CX-2929

🧰 Changes

Retake of #1334 because now we have legacy variable tokenizer ready and no longer need to pass in the legacy variables mapping.

Refactors the slug generation logic for headings (which will be used for anchor section links) in MDXish so that if it contains a legacy <<>> or {} variable, the generated slug will use the variable name instead of the variable value. The change is in the heading id generation, which later will be converted to slugs in renderMdxish.

We wanted to this to make the anchor slug more stable. In legacy, the variable part will actually get dropped in the slug generation, so it can unexpectedly clash with other headings & look incomplete. In mdxish, before it was resolving the variable value in the slugs, which means the slugs can change if the value change, and a hardcoded link can get outdated without the user knowing.

This is the first step in addressing this Akamai QA issue: https://linear.app/readme-io/issue/CX-2867/links-to-section-headings-that-involve-variables-personalized-docs

Note:
This change will modify the anchor slug url if it has variables in them, which would make hardcoded links not work for those cases. But given MDXish hasn't been on for a long time, hopefully there's not much customers doing that yet.

🧬 QA & Testing

  1. I think it's best to test this by locally linking this branch to readme
  2. In the MDXish RDMD here, remove the opts.mdxish part to avoid preprocessing legacy variables
  3. In an mdxish project in the site, create several H1-H3 headings that contain legacy <<>> and {} variables in them
  4. When hovering the anchor logo next to the headings, look at the bottom left of your screen for the slug. The slug should use the variable name and not the value

@eaglethrost eaglethrost changed the base branch from next to dimas/RM-15239-parse-legacy-vars-in-mdxish February 13, 2026 14:47
@eaglethrost eaglethrost changed the title refactor(mdxish): fallback to variable name for heading slug generation refactor(mdxish): use variable name for heading slug generation Feb 13, 2026
if (node.properties.isLegacy) {
return node.properties.name as string;
}
return `{user.${node.properties.name}}`;
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.

From my understanding modern {} variables are always prepended by user.

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.

Correct

* Uses variable names for the id if available
*/
const generateSlugForHeadings = () => (tree: Root) => {
const slugger = new GithubSlugger();
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.

Using git slugger to ensure the heading style is consistent with the git style (lowercase words combined by -). We technically can construct them ourselves without any library, but I think this abstracts them away, reduce chance of errors, and make the slug more consistent.

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.

I think this is fine, but am concerned around any breaking changes from the way slugs are constructed on legacy. Not in the way vars are resolved like we're discussing here but in edge case formatting.

If we ignore the var resolution question do you think this will match the way slugs are constructed on legacy?

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.

Yes it does, at least from my testing so far it seems to be match. I'll add more tests for this to verify

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.

Updated the mdxish-heading-slugs-test.ts tests to also check if it matches legacy slugs

@eaglethrost eaglethrost marked this pull request as ready for review February 13, 2026 15:14
@eaglethrost eaglethrost requested review from kevinports and rafegoldberg and removed request for rafegoldberg February 13, 2026 15:14
@rafegoldberg
Copy link
Copy Markdown
Contributor

Haven't QAed yet, but here's a random list of things I'd check/vaguely remember having caused issues in the past:

  • how does this work with emojis?
  • how does this work with multiple identical heading texts?
  • how different are these anchor slugs from the old ones? (i.e. will this break preexisting anchored URLs that customers might be referencing elsewhere)

@rafegoldberg
Copy link
Copy Markdown
Contributor

Also, is there a ticket for this that we can link?

@eaglethrost
Copy link
Copy Markdown
Contributor Author

eaglethrost commented Feb 13, 2026

Haven't QAed yet, but here's a random list of things I'd check/vaguely remember having caused issues in the past:

  • how does this work with emojis?
  • how does this work with multiple identical heading texts?
  • how different are these anchor slugs from the old ones? (i.e. will this break preexisting anchored URLs that customers might be referencing elsewhere)

Linked the ticket! To answer your questions:

  1. Emojis will get dropped in the id / slug. I don’t think it’s possible to have emoji slugs? They all get dropped in legacy & mdx
  2. Same headings will have an auto incrementing number at the end so they can be unique. The Git library handles this
  3. Compared to the legacy slugs, the only difference would only be for headings with variables on it, other than that the slugs will be the same

commit e657a21
Author: eagletrhost <dimazanugrah12@gmail.com>
Date:   Mon Feb 16 19:51:12 2026 +1100

    refactor: clean code & comment

commit c28853d
Author: eagletrhost <dimazanugrah12@gmail.com>
Date:   Mon Feb 16 19:40:18 2026 +1100

    test: fix legacy

commit 7574b19
Author: eagletrhost <dimazanugrah12@gmail.com>
Date:   Mon Feb 16 18:36:04 2026 +1100

    feat: glossary adjustments

commit 6e92df0
Author: eagletrhost <dimazanugrah12@gmail.com>
Date:   Mon Feb 16 18:13:02 2026 +1100

    feat: parse legacy vars in codes & api header block
@eaglethrost
Copy link
Copy Markdown
Contributor Author

Demo & explanation of what the legacy vs mdxish slugs will look like once we stop preprocessing the variables in the frontend: https://www.loom.com/share/0a922e7cde5245c39870f70a93b2293e

Base automatically changed from dimas/RM-15239-parse-legacy-vars-in-mdxish to next February 19, 2026 12:43
expect(headings).toHaveLength(1);
expect(headings[0].id).toBe('hello-world-');

const legacyTree = mdastV6Wrapper(md) as Root;
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.

Added tests to check if it matches with legacy id / slugs

@eaglethrost eaglethrost merged commit 61a97d3 into next Feb 20, 2026
14 of 15 checks passed
@eaglethrost eaglethrost deleted the dimas/CX-2929-mdxish-heading-stabilize-slug-generation branch February 20, 2026 01:17
rafegoldberg pushed a commit that referenced this pull request Feb 20, 2026
## Version 13.3.0
### ✨ New & Improved

* **mdxish:** add legacy variable tokenizer ([#1339](#1339)) ([8e8b11b](8e8b11b))
* add option to perserve variable syntax in plain text compiler ([#1345](#1345)) ([5ab350e](5ab350e))
* **mdxish:** resolve variables in code blocks ([#1350](#1350)) ([a6460f8](a6460f8))
* **mdxish:** use variable name for heading slug generation ([#1340](#1340)) ([61a97d3](61a97d3))

<!--SKIP CI-->
@rafegoldberg
Copy link
Copy Markdown
Contributor

This PR was released!

🚀 Changes included in v13.3.0

HugoHSun added a commit that referenced this pull request Feb 26, 2026
[![PR App][icn]][demo] | Fix CX-98
:-------------------:|:----------:

## 🧰 Changes

Since we can now distinguish legacy variable vs mdx variable
(#1340), as well as allowing
wild variables in bracket notation
(readmeio/readme#17315). We should add support
for plain to keep original syntax as is, instead of serialising
everything to {user.}.

## 🧬 QA & Testing

Unit tests

- [Broken on production][prod].
- [Working in this PR app][demo].


[demo]: https://markdown-pr-PR_NUMBER.herokuapp.com
[prod]: https://SUBDOMAIN.readme.io
[icn]:
https://user-images.githubusercontent.com/886627/160426047-1bee9488-305a-4145-bb2b-09d8b757d38a.svg
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants