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

How to write an async renderer? #2626

Closed
cyrus-and opened this issue Oct 26, 2022 · 6 comments
Closed

How to write an async renderer? #2626

cyrus-and opened this issue Oct 26, 2022 · 6 comments
Labels

Comments

@cyrus-and
Copy link

Marked version: v4.1.1

Describe the bug

Despite #2474 fixes #458, I don't see how I can write an async renderer, it seems that the former merely allows to write an async version of the walkTokens function.

To Reproduce

Steps to reproduce the behavior:

<script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
<script>
  marked.use({
      renderer: {
          async link(href, title, text) {
              return 'x';
          }
      }
  });
  alert(marked.parse('[a](b)'));
</script>

Expected behavior

I expected to see x in the output, and not <p>[object Promise]</p>.

@UziTech
Copy link
Member

UziTech commented Oct 26, 2022

it seems that the former merely allows to write an async version of the walkTokens function.

That is essentially what it does. Having async functions in the renderer or tokenizer would require lots of duplicate code in order to not break things or slow down marked for anyone who doesn't need it to be async.

You can see an example of how to make marked async in the docs.

@cyrus-and
Copy link
Author

So the question remains, how can I achieve the same using walkTokens only? AFAIK I cannot change the token body with that, the example you linked works (for links) for the title property, if I try to change the text property it doesn't, and I think it makes sense that way.

@UziTech
Copy link
Member

UziTech commented Oct 27, 2022

Can you give some example markdown and expected output?

@cyrus-and
Copy link
Author

I basically want to override the link text in certain conditions, and using a renderer would work fine, the problem is that I need to perform some async operations in doing that.

From:

[some-text](url)

to:

<a href="url">some-other-text</a>

@UziTech
Copy link
Member

UziTech commented Oct 27, 2022

The text for a link is tokenized since it can have other markdown tokens inside of it. Here is an example that changes the link text and re tokenizes it:

import { marked } from 'marked';

const myAsyncExtension = {
  async: true,
  async walkTokens(token) {
    if (token.type === 'link') {
      const newText = await somethingAsync(token);

      // `this` in a walkTokens function is `marked`.
      // tokenize the `newText` so the renderer can render it correctly.
      // `newText` can be inline markdown.
      token.tokens = this.Lexer.lexInline(newText)
    }
  }
};

async function somethingAsync(token) {
  await new Promise(r => setTimeout(r, 100));
  return token.text + ' async';
}

marked.use(myAsyncExtension);

const md = `
[test](/url "title")
`;

console.log(await marked.parse(md));
// <p><a href="/url" title="title">test async</a></p>

@cyrus-and
Copy link
Author

Awesome, that will do it. Thank you so much for the quick support!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants