Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 29 additions & 0 deletions build/shared/heading-slug.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* @file The anchor a heading gets on the built site.
* @author The OpenINF Authors & Friends
* @license MIT OR Apache-2.0 OR BlueOak-1.0.0
* @module {type ES6Module} build/shared/heading-slug
*/

// cspell:ignore fetchcontent

/**
* Turns a heading's text into its anchor the way GitHub does: lowercased,
* punctuation other than `-` and `_` dropped, and each space a `-`.
*
* The links that point at a heading are written to that rule, by people used
* to GitHub and by TypeDoc, whose reference links to `logLevel?` as
* `#loglevel` and to `fetchContent()` as `#fetchcontent`. markdown-it-anchor
* keeps the punctuation instead and percent-encodes it, so those headings were
* `#loglevel%3F` and `#fetchcontent()`, and the links reached the top of the
* page rather than the heading.
* @param {string} text The heading's text content.
* @returns {string} The anchor, without the `#`.
*/
export function headingSlug(text: string): string {
return text
.trim()
.toLowerCase()
.replace(/[^\p{L}\p{M}\p{N}\p{Pc}\- ]/gu, '')
.replace(/ /g, '-');
}
42 changes: 42 additions & 0 deletions build/shared/heading-slug.test.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* @file Tests for the heading anchor rule.
* @author The OpenINF Authors & Friends
* @license MIT OR Apache-2.0 OR BlueOak-1.0.0
* @module {type ES6Module} build/shared/heading-slug.test
*/

// cspell:ignore fetchcontent

import { strictEqual } from 'node:assert/strict';
import { describe, test } from 'node:test';
import { headingSlug } from '@openinf/portal/build/heading-slug';

describe('headingSlug', () => {
test('matches the anchors TypeDoc links to', () => {
strictEqual(headingSlug('logLevel?'), 'loglevel');
strictEqual(headingSlug('fetchContent()'), 'fetchcontent');
strictEqual(headingSlug('set()?'), 'set');
strictEqual(headingSlug('submodule_git_url?'), 'submodule_git_url');
});

test('drops punctuation as GitHub does, keeping hyphens', () => {
strictEqual(
headingSlug('Show the command, not the ceremony'),
'show-the-command-not-the-ceremony'
);
strictEqual(
headingSlug('Required items (commands, arguments, etc.)'),
'required-items-commands-arguments-etc'
);
strictEqual(headingSlug('Questions or thoughts?'), 'questions-or-thoughts');
strictEqual(headingSlug('Before-and-after'), 'before-and-after');
});

test('keeps letters and digits from any script', () => {
strictEqual(headingSlug('Caf茅 na茂ve 2026'), 'caf茅-na茂ve-2026');
});

test('turns every space into a hyphen', () => {
strictEqual(headingSlug(' a b '), 'a--b');
});
});
3 changes: 2 additions & 1 deletion eleventy.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { readdir, readFile, unlink, writeFile } from 'node:fs/promises';
import { extname, join, parse as pathParse } from 'node:path';
import { EleventyI18nPlugin } from '@11ty/eleventy';
import { PATHS } from '@openinf/portal/build/constants';
import { headingSlug } from '@openinf/portal/build/heading-slug';
import { hasViewBox, replaceInlineSvg } from '@openinf/portal/build/inline-svg';
import { sanitizeSdkHtml } from '@openinf/portal/build/sdk-docs';
import autoprefixer from 'autoprefixer';
Expand Down Expand Up @@ -76,7 +77,7 @@ export default async function (eleventyConfig) {

eleventyConfig.amendLibrary('md', (md) => {
md.set({ highlight });
md.use(markdownItAnchor);
md.use(markdownItAnchor, { slugify: headingSlug });
md.use(markdownItFootnote);
// `> [!NOTE]` and the rest become a titled callout rather than a
// blockquote opening on the literal marker. The icons it ships with come
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
"exports": {
"./build/commit-message": "./build/shared/commit-message.mts",
"./build/constants": "./build/shared/constants.mts",
"./build/heading-slug": "./build/shared/heading-slug.mts",
"./build/inline-svg": "./build/shared/inline-svg.mts",
"./build/landing": "./build/shared/landing.mts",
"./build/pull-request": "./build/shared/pull-request.mts",
Expand Down
Loading