pablo-abc / svelte-markdown

Markdown parser to svelte components
MIT License
360 stars 50 forks source link

feat: add extensions support #38

Closed genericFJS closed 2 years ago

genericFJS commented 2 years ago

Quick and dirty: Add "use" parameter which allows extensions (see #17 ).

Example usage (replaces token [[latex…]] with a colored span): File App.svelte

<script>
  import SvelteMarkdown from "svelte-markdown";
  import LatexMarkdown from "./LatexMarkdown.svelte";

  const latexTokenizerExtension = {
    name: "latex",
    level: "inline",
    start(src) {
      return src.match(/\[\[/)?.index;
    },
    tokenizer(src, tokens) {
      const rule = /^\[\[latex\s*(?:color="(.*)")?\]\]/;
      const match = rule.exec(src);
      if (match) {
        console.log(match[1]);
        return {
          type: "latex",
          raw: match[0],
          text: match[0],
          color: match[1],
        };
      }
    },
  };

  const use = { extensions: [latexTokenizerExtension] };

  const renderers = {
    latex: LatexMarkdown,
  };

  const source = `
  # This is a header

This is a paragraph.

This is red [[latex color="red"]] text.

* This is a list
* With two items
  1. And a sublist
  2. That is ordered
    * With another
    * Sublist inside

| And this is | A table |
|-------------|---------|
| With two    | columns |`;
</script>

<SvelteMarkdown {source} {use} {renderers} />

Imported file LatexMarkdown.svelte

<script>
  export let color;
</script>

<span style={"color: " + color}>LaTeX</span>
genericFJS commented 2 years ago

Added a test and documentation.

pablo-abc commented 2 years ago

This looks great! Thanks a lot! I just left a couple of questions

genericFJS commented 2 years ago

While testing a bit more I found a huge problem with my approach: by using marked.use I manipulate the global options. Marked therefore keeps the options (between tests). That means that I can not pass an extension in one test and have a following test where I expect the custom token not to be replaced.

genericFJS commented 2 years ago

I think we should close this pull request, since marked.use has a lot of side effects and implementing it side effect free seems too big a hassle. Since marked.use transformes the extensions to another structure into the global marked.defaults options, it's easier if SvelteMarkdown does not support extensions directly, but the user may generate his own extension-enriched options and pass it as options to the SvelteMarkdown component:

<script>
  // [… as in first comment]

  // let marked save extension information to global options:
  marked.use({ extensions: [latexTokenizerExtension] });
  // use global marked options as parameter for SvelteMarkdown-component
  const options = marked.defaults;
</script>

<!-- works without this PR -->
<SvelteMarkdown {source} {options} {renderers} />
genericFJS commented 2 years ago

Closing in favor of manually doing it by passing the appropriate options.