Skip to content

Commit

Permalink
feat: match anchors within paragraphs
Browse files Browse the repository at this point in the history
  • Loading branch information
main-kun authored and moki committed Nov 30, 2023
1 parent 7712685 commit 19551c2
Show file tree
Hide file tree
Showing 5 changed files with 67 additions and 46 deletions.
47 changes: 47 additions & 0 deletions src/transform/plugins/block-anchor/block-anchor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import StateCore from 'markdown-it/lib/rules_core/state_core';
import Token from 'markdown-it/lib/token';

const pattern = /^{%[^\S\r\n]*anchor[^\S\r\n]+([\w-]+)[^\S\r\n]*%}$/;
export const TOKEN_NAME = 'anchor';

function matchOpenToken(tokens: Token[], i: number) {
return (
tokens[i].type === 'paragraph_open' &&
tokens[i + 1].type === 'inline' &&
tokens[i + 2].type === 'paragraph_close' &&
pattern.exec(tokens[i + 1].content)
);
}

function createAnchorToken(state: StateCore, anchorId: string, position: number) {
const token = new state.Token(TOKEN_NAME, '', 0);
token.map = state.tokens[position].map;
token.markup = state.tokens[position].markup;
token.content = anchorId;
return token;
}

export function replaceTokens(state: StateCore) {
const blockTokens = state.tokens;
// i hate the idea of splicing the array while we're iterating over it
// so first lets find all the places where we will need to splice it and then actually do the splicing
const splicePointsMap: Map<number, string> = new Map();
for (let i = 0; i < blockTokens.length; i++) {
const match = matchOpenToken(blockTokens, i);

if (!match) {
continue;
}

splicePointsMap.set(i, match[1]);
}
splicePointsMap.forEach((anchorId, position) => {
blockTokens.splice(position, 3, createAnchorToken(state, anchorId, position));
});
}

export function renderTokens(tokens: Token[], idx: number) {
const token = tokens[idx];
const id = token.content;
return `<a id=${id}></a>`;
}
11 changes: 11 additions & 0 deletions src/transform/plugins/block-anchor/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import MarkdownIt from 'markdown-it';
import {renderTokens, replaceTokens, TOKEN_NAME} from './block-anchor';

const blockAnchor = (md: MarkdownIt) => {
md.core.ruler.push(TOKEN_NAME, replaceTokens);
md.renderer.rules[TOKEN_NAME] = renderTokens;

return md;
};

export default blockAnchor;
31 changes: 0 additions & 31 deletions src/transform/plugins/detached-anchor/detached-anchor.ts

This file was deleted.

11 changes: 0 additions & 11 deletions src/transform/plugins/detached-anchor/index.ts

This file was deleted.

13 changes: 9 additions & 4 deletions test/detached-anchor.test.ts → test/block-anchor.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import transform from '../src/transform';
import plugin from '../src/transform/plugins/detached-anchor';
import plugin from '../src/transform/plugins/block-anchor';
import anchorsPlugin from '../src/transform/plugins/anchors';

let transformYfm = (text: string) => {
Expand All @@ -11,10 +11,15 @@ let transformYfm = (text: string) => {
return html;
};

describe('detached-anchor', function () {
describe('block-anchor', function () {
describe('simple rendering', () => {
it('should render an a tag', () => {
expect(transformYfm('{#my-anchor}')).toBe('<a id="my-anchor"></a>');
expect(transformYfm('{%anchor my-anchor%}')).toBe('<a id="my-anchor"></a>');
});
it('does not consume things it should not', () => {
expect(transformYfm('# Heading \n {%anchor my-anchor%} \n # Other heading')).toContain(
'Other heading',
);
});
});
describe('with heading anchors', () => {
Expand All @@ -25,7 +30,7 @@ describe('detached-anchor', function () {
return html;
};
it('does not conflict with heading anchors', () => {
expect(transformYfm('# Heading {#heading-anchor} \n {#my-anchor}')).toBe(
expect(transformYfm('# Heading {#heading-anchor} \n {%anchor my-anchor%}')).toBe(
'<h1 id="heading-anchor">' +
'<a href="#heading-anchor" class="yfm-anchor" aria-hidden="true">' +
'<span class="visually-hidden">Heading</span></a>Heading</h1>\n' +
Expand Down

0 comments on commit 19551c2

Please sign in to comment.