Skip to content

Commit d657678

Browse files
committed
add tests, fix options format, add documentation
1 parent 852046d commit d657678

File tree

6 files changed

+56
-11
lines changed

6 files changed

+56
-11
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,12 @@ const mdx = require('@mdx-js/mdx')
4646
const {allPlugins} = require('@hashicorp/remark-plugins')
4747

4848
console.log(mdx.sync('some markdown content', {
49-
remarkPlugins: allPlugins
49+
remarkPlugins: allPlugins(/* options */)
5050
})
5151
```
5252
53+
Plugin options can be passed to `allPlugins` as an object, with the keys being plugin names. For example, to pass options to `headingLinkable`, you could call `allPlugins({ headingLinkable: { foo: 'bar' } })`.
54+
5355
If you are using `next-hashicorp`, all of these plugins will be included by default.
5456
5557
## Publishing

index.js

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,11 @@ module.exports = {
1414
}
1515

1616
// for easy use of everything at the same time
17-
module.exports.allPlugins = ({ headingLinkable } = {}) => [
17+
module.exports.allPlugins = ({
18+
headingLinkable: headingLinkableOptions
19+
} = {}) => [
1820
includeMarkdown,
19-
headingLinkable(headingLinkable),
21+
[headingLinkable, headingLinkableOptions],
2022
inlineCodeLinkable,
2123
paragraphCustomAlerts,
2224
typography

index.test.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,7 @@ it('api works as intended', () => {
66
expect(remarkPlugins.paragraphCustomAlerts).toBeTruthy()
77
expect(remarkPlugins.typography).toBeTruthy()
88
expect(remarkPlugins.includeMarkdown).toBeTruthy()
9-
expect(remarkPlugins.allPlugins.length).toBe(5)
9+
expect(remarkPlugins.allPlugins().length).toBe(5)
10+
// passes options to headingLinkable correctly
11+
expect(remarkPlugins.allPlugins({ headingLinkable: 'foo' })[1][1]).toBe('foo')
1012
})

plugins/heading-linkable/README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,3 +41,9 @@ Content here...
4141
```
4242

4343
Since the `__target` element actually carries the id rather than the headline, it can be positioned independently to pad the headline off the top of the page if necessary, which is the case any time we use a "sticky" navigation.
44+
45+
## Options
46+
47+
- `compatibilitySlug` _(optional)_ - if present, will generate an additional target element using a custom slug creation algorithm. Accepts a function with the following signature `fn(text: string)`. The `text` argument is the headline text, if the `compatibilitySlug` function generates an idential slug as the default, it will not be added at all.
48+
49+
> **NOTE:** Be conscious of duplicate tracking with your compatibility function. If it needs to keep track of existing slugs on the page to avoid duplicates, it must implement that functionality on its own. Default slugs are not exposed to the `compatibilitySlug` function because this offers a footgun that can easily break compatibility. The `compatibilitySlug` function should operate entirely in its own sphere -- if it happens to generate a duplicate slug, the plugin itself will remove it as compatibility isn't necessary in that instance.

plugins/heading-linkable/index.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,13 @@ module.exports = function headingLinkablePlugin({ compatibilitySlug } = {}) {
1919
})
2020

2121
if (compatibilitySlug) {
22-
const slug2 = compatibilitySlug(text, links)
23-
node.children.unshift({
24-
type: 'html',
25-
value: `<a class="__target_compat" id="${slug2}" aria-hidden="true"></a>`
26-
})
22+
const slug2 = compatibilitySlug(text)
23+
if (slug !== slug2) {
24+
node.children.unshift({
25+
type: 'html',
26+
value: `<a class="__target_compat" id="${slug2}" aria-hidden="true"></a>`
27+
})
28+
}
2729
}
2830

2931
node.children.unshift({

plugins/heading-linkable/index.test.js

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,13 @@ describe('heading-linkable', () => {
1111
.processSync('# hello world')
1212
.toString()
1313
).toMatch(
14-
'<h1><a class="anchor" href="#hello-world" aria-label="hello world permalink">»</a><a class="__target" id="hello-world" aria-hidden="true"></a>hello world</h1>'
14+
[
15+
'<h1>',
16+
'<a class="anchor" href="#hello-world" aria-label="hello world permalink">»</a>',
17+
'<a class="__target" id="hello-world" aria-hidden="true"></a>',
18+
'hello world',
19+
'</h1>'
20+
].join('')
1521
)
1622
})
1723

@@ -106,7 +112,32 @@ describe('heading-linkable', () => {
106112
.processSync('# hello world')
107113
.toString()
108114
).toMatch(
109-
'<h1><a class="anchor" href="#hello-world" aria-label="hello world permalink">»</a><a class="__target_compat" id="foo" aria-hidden="true"></a><a class="__target" id="hello-world" aria-hidden="true"></a>hello world</h1>'
115+
[
116+
'<h1>',
117+
'<a class="anchor" href="#hello-world" aria-label="hello world permalink">»</a>',
118+
'<a class="__target_compat" id="foo" aria-hidden="true"></a>',
119+
'<a class="__target" id="hello-world" aria-hidden="true"></a>',
120+
'hello world',
121+
'</h1>'
122+
].join('')
123+
)
124+
})
125+
126+
test('does not render duplicate compatibility slugs', () => {
127+
expect(
128+
remark()
129+
.use(headingLinkable, { compatibilitySlug: slug => 'hello-world' })
130+
.use(html)
131+
.processSync('# hello world')
132+
.toString()
133+
).toMatch(
134+
[
135+
'<h1>',
136+
'<a class="anchor" href="#hello-world" aria-label="hello world permalink">»</a>',
137+
'<a class="__target" id="hello-world" aria-hidden="true"></a>',
138+
'hello world',
139+
'</h1>'
140+
].join('')
110141
)
111142
})
112143
})

0 commit comments

Comments
 (0)