Skip to content
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

Option to offset heading levels #1657

Closed
jakearchibald opened this issue May 1, 2020 · 8 comments
Closed

Option to offset heading levels #1657

jakearchibald opened this issue May 1, 2020 · 8 comments

Comments

@jakearchibald
Copy link

Describe the feature
An option, like baseHeadingLevel: 2, which would turn # into <h2>, and ## into <h3>.

Why is this feature necessary?
Sometimes a single piece of markdown output will be used in a larger HTML page, so the top level heading an a markdown file won't equal an <h1> in the target page.

Describe alternatives you've considered
You could just alter the markdown file itself, but that's tricky if you're outputting the same markdown in multiple places where the heading levels should be different.

You could write a heading renderer, but that can get tricky if you already have a heading renderer that's doing something other than just changing the heading level.

@styfle
Copy link
Member

styfle commented May 2, 2020

Hi Jake,

That’s an interesting idea!

I think you should be able to achieve this result with marked.use().

Will this solve your problem?

@UziTech
Copy link
Member

UziTech commented May 2, 2020

We are trying to prevent feature creep and slim marked down to be an extensible module that just handles the core functionality of converting markdown to html according the specs. We will be deprecating any option that can be moved into an extension soon.

You can create an extension that would handle this:

// marked-base-heading
const marked = require('marked');
module.exports = function (base = 1) {
  return {
    renderer: {
      heading(text, level, raw, slugger) {
        const renderer = new marked.Renderer(this.options);
        return renderer.heading(text, level + base - 1, raw, slugger);
      }
    }
  };
}
// index.js
const marked = require('marked');
marked.use(require('marked-base-heading')(2));

const html = marked('# heading 2');
// <h2 id="heading-2">heading 2</h2>
...

@jakearchibald
Copy link
Author

Interesting! I didn't realise this.options could be used in this way. Does this work even if there are other heading renderers?

The docs mention that a renderer function can return false to defer to the next handler, maybe there needs to be an example of this arg-transforming behaviour.

@UziTech
Copy link
Member

UziTech commented May 2, 2020

There can only be one renderer for each token, if you return false it will call the previous renderer but there is no way to change the arguments for the previous renderer.

You could also change the level in the tokens before they get to the renderer either by adding tokenizers for heading and lheading that call the original tokenizers and change the depth, or by getting the tokens with marked.lexer and iterating over each token to change the depth property before sending the tokens to marked.parser

function iterateTokens(tokens, pred) {
  for (const token of tokens) {
    pred(token);
    if (token.tokens) {
      iterateTokens(token.tokens, pred);
    }
  }
}

const tokens = marked.lexer(markdown, options);

iterateTokens(tokens, (token) => {
  if (token.type === 'heading') {
    token.depth += 1;
  }
});

const html = marked.parser(tokens, options);

@UziTech
Copy link
Member

UziTech commented May 2, 2020

I just realized that iterateTokens function will not find tokens in a table and list. Maybe it would be worth it to create an easier way to iterate over the tokens.

@UziTech
Copy link
Member

UziTech commented May 4, 2020

PR #1664 adds a marked.iterateTokens function that will allow you to run a function for every token.

@jakearchibald
Copy link
Author

Yeah, that works, as long as it's clear that the tokens are mutable.

@UziTech
Copy link
Member

UziTech commented May 21, 2020

walkTokens should be available in v1.1.0. I used this as the walkTokens example
https://marked.js.org/#/USING_PRO.md#walk-tokens

@UziTech UziTech closed this as completed May 21, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants