-
Notifications
You must be signed in to change notification settings - Fork 40
feat: restore legacy anchor alias to preserve old links #699
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| 'use strict'; | ||
|
|
||
| import assert from 'node:assert/strict'; | ||
| import { describe, it } from 'node:test'; | ||
|
|
||
| import { createLegacySlugger } from '../slugger.mjs'; | ||
|
|
||
| describe('createLegacySlugger', () => { | ||
| it('prefixes with api stem and uses underscores', () => { | ||
| const slugger = createLegacySlugger(); | ||
| assert.strictEqual( | ||
| slugger.getLegacySlug('File System', 'fs'), | ||
| 'fs_file_system' | ||
| ); | ||
| }); | ||
|
|
||
| it('replaces special characters with underscores', () => { | ||
| const slugger = createLegacySlugger(); | ||
| assert.strictEqual( | ||
| slugger.getLegacySlug('fs.readFile(path)', 'fs'), | ||
| 'fs_fs_readfile_path' | ||
| ); | ||
| }); | ||
|
|
||
| it('strips leading and trailing underscores', () => { | ||
| const slugger = createLegacySlugger(); | ||
| assert.strictEqual(slugger.getLegacySlug('Hello', 'fs'), 'fs_hello'); | ||
| }); | ||
|
|
||
| it('prefixes with underscore when result starts with non-alpha', () => { | ||
| const slugger = createLegacySlugger(); | ||
| assert.strictEqual( | ||
| slugger.getLegacySlug('123 test', '0num'), | ||
| '_0num_123_test' | ||
| ); | ||
| }); | ||
|
|
||
| it('deduplicates with a counter for identical titles', () => { | ||
| const slugger = createLegacySlugger(); | ||
| assert.strictEqual(slugger.getLegacySlug('Hello', 'fs'), 'fs_hello'); | ||
| assert.strictEqual(slugger.getLegacySlug('Hello', 'fs'), 'fs_hello_1'); | ||
| assert.strictEqual(slugger.getLegacySlug('Hello', 'fs'), 'fs_hello_2'); | ||
| assert.strictEqual(slugger.getLegacySlug('World', 'fs'), 'fs_world'); | ||
| }); | ||
| }); |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,6 +5,7 @@ import { u as createTree } from 'unist-builder'; | |||||||||||||||||||||||||
| import { SKIP, visit } from 'unist-util-visit'; | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| import buildExtraContent from './buildExtraContent.mjs'; | ||||||||||||||||||||||||||
| import { createLegacySlugger } from './slugger.mjs'; | ||||||||||||||||||||||||||
| import getConfig from '../../../utils/configuration/index.mjs'; | ||||||||||||||||||||||||||
| import { | ||||||||||||||||||||||||||
| GITHUB_BLOB_URL, | ||||||||||||||||||||||||||
|
|
@@ -20,12 +21,14 @@ import { QUERIES, UNIST } from '../../../utils/queries/index.mjs'; | |||||||||||||||||||||||||
| * @param {import('unist').Parent} parent The parent node of the current node | ||||||||||||||||||||||||||
| * @returns {import('hast').Element} The HTML AST tree of the heading content | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| const buildHeading = ({ data, children, depth }, index, parent) => { | ||||||||||||||||||||||||||
| const buildHeading = ({ data, children, depth }, index, parent, legacySlug) => { | ||||||||||||||||||||||||||
| // Creates the heading element with the heading text and the link to the heading | ||||||||||||||||||||||||||
| const headingElement = createElement(`h${depth + 1}`, [ | ||||||||||||||||||||||||||
| // The inner Heading markdown content is still using Remark nodes, and they need | ||||||||||||||||||||||||||
| // to be converted into Rehype nodes | ||||||||||||||||||||||||||
| ...children, | ||||||||||||||||||||||||||
| // Legacy anchor alias to preserve old external links | ||||||||||||||||||||||||||
| createElement('span', createElement(`a#${legacySlug}`)), | ||||||||||||||||||||||||||
| // Creates the element that references the link to the heading | ||||||||||||||||||||||||||
| // (The `#` anchor on the right of each Heading section) | ||||||||||||||||||||||||||
| createElement( | ||||||||||||||||||||||||||
|
|
@@ -220,6 +223,8 @@ const buildMetadataElement = (node, remark) => { | |||||||||||||||||||||||||
| * @param {import('unified').Processor} remark The Remark instance to be used to process | ||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||
| export default (headNodes, metadataEntries, remark) => { | ||||||||||||||||||||||||||
| const legacySlugger = createLegacySlugger(); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Creates the root node for the content | ||||||||||||||||||||||||||
| const parsedNodes = createTree( | ||||||||||||||||||||||||||
| 'root', | ||||||||||||||||||||||||||
|
|
@@ -229,7 +234,13 @@ export default (headNodes, metadataEntries, remark) => { | |||||||||||||||||||||||||
| const content = structuredClone(entry.content); | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Parses the Heading nodes into Heading elements | ||||||||||||||||||||||||||
| visit(content, UNIST.isHeading, buildHeading); | ||||||||||||||||||||||||||
| visit(content, UNIST.isHeading, (node, index, parent) => { | ||||||||||||||||||||||||||
| const legacySlug = legacySlugger.getLegacySlug( | ||||||||||||||||||||||||||
| node.data.text, | ||||||||||||||||||||||||||
| entry.api | ||||||||||||||||||||||||||
| ); | ||||||||||||||||||||||||||
| buildHeading(node, index, parent, legacySlug); | ||||||||||||||||||||||||||
| }); | ||||||||||||||||||||||||||
|
Comment on lines
+237
to
+243
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| // Parses the Blockquotes into Stability elements | ||||||||||||||||||||||||||
| // This is treated differently as we want to preserve the position of a Stability Index | ||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,48 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| 'use strict'; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const notAlphaNumerics = /[^a-z0-9]+/g; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const edgeUnderscores = /^_+|_+$/g; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const notAlphaStart = /^[^a-z]/; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Deduplicates legacy slugs by appending an incremented counter. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Adapted from maintainer suggestion to preserve `id` on first occurrence. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Remember to double-check AI output before using it in a PR
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sorry for this negligence, I was re-verifying the logic using AI. Will take care in future! |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param {Record<string, number>} counters | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @returns {(id: string) => string} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const legacyDeduplicator = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| (counters = { __proto__: null }) => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| id => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| counters[id] ??= -1; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const count = ++counters[id]; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return count > 0 ? `${id}_${count}` : id; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Creates a stateful slugger for legacy anchor links. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @returns {{ getLegacySlug: (text: string, apiStem: string) => string }} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| export const createLegacySlugger = () => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const deduplicate = legacyDeduplicator(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /** | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * Generates a legacy-style slug to preserve old anchor links. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param {string} text The heading text | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @param {string} apiStem The API file identifier (e.g. 'fs', 'http') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| * @returns {string} The legacy slug | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| */ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| getLegacySlug: (text, apiStem) => { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| const id = `${apiStem}_${text}` | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .toLowerCase() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .replace(notAlphaNumerics, '_') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .replace(edgeUnderscores, '') | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| .replace(notAlphaStart, '_$&'); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return deduplicate(id); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+1
to
+48
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make sure to double check my |
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.