Skip to content

Markdown configuration: marked extensions don't work #1874

Closed
@dzylikecode

Description

@dzylikecode

Bug Report

  • OS: windows
  • browser: Google Chrome 104.0.5112.102

In order to customize the parsing rules, I follow the advice of the document about Markdown configuration and read the marked documentation. However, when I wanna reproduce the example to add a custom syntax to generate <dl> description lists, it doesn't work.

Steps to reproduce

  • configure the docsify

    window.$docsify = {
      markdown: function (marked, oldRenderer) {
        let renderer = {
          // block
          code: function (code, infostring, escaped) {
            return oldRenderer.code.apply(this, arguments);
          },
          blockquote: function (quote) {
            return oldRenderer.blockquote.apply(this, arguments);
          },
          html: function (html) {
            return oldRenderer.html.apply(this, arguments);
          },
          heading: function (text, level, raw, slugger) {
            return oldRenderer.heading.apply(this, arguments);
          },
          hr: function () {
            return oldRenderer.hr.apply(this, arguments);
          },
          list: function (body, ordered, start) {
            return oldRenderer.list.apply(this, arguments);
          },
          listitem: function (text, task, checked) {
            return oldRenderer.listitem.apply(this, arguments);
          },
          checkbox: function (checked) {
            return oldRenderer.checkbox.apply(this, arguments);
          },
          paragraph: function (text) {
            return oldRenderer.paragraph.apply(this, arguments);
          },
          table: function (header, body) {
            return oldRenderer.table.apply(this, arguments);
          },
          tablerow: function (content) {
            return oldRenderer.tablerow.apply(this, arguments);
          },
          tablecell: function (content, flags) {
            return oldRenderer.tablecell.apply(this, arguments);
          },
          // inline
          strong: function (text) {
            return oldRenderer.strong.apply(this, arguments);
          },
          em: function (text) {
            return oldRenderer.em.apply(this, arguments);
          },
          codespan: function (code) {
            return oldRenderer.codespan.apply(this, arguments);
          },
          br: function () {
            return oldRenderer.br.apply(this, arguments);
          },
          del: function (text) {
            return oldRenderer.del.apply(this, arguments);
          },
          link: function (href, title, text) {
            return oldRenderer.link.apply(this, arguments);
          },
          image: function (href, title, text) {
            return oldRenderer.image.apply(this, arguments);
          },
          text: function (text) {
            return oldRenderer.text.apply(this, arguments);
          },
        };
        const descriptionList = {
          name: "descriptionList",
          level: "block", // Is this a block-level or inline-level tokenizer?
          start(src) {
            return src.match(/:[^:\n]/)?.index;
          }, // Hint to Marked.js to stop and check for a match
          tokenizer(src, tokens) {
            const rule = /^(?::[^:\n]+:[^:\n]*(?:\n|$))+/; // Regex for the complete token, anchor to string start
            const match = rule.exec(src);
            if (match) {
              const token = {
                // Token to generate
                type: "descriptionList", // Should match "name" above
                raw: match[0], // Text to consume from the source
                text: match[0].trim(), // Additional custom properties
                tokens: [], // Array where child inline tokens will be generated
              };
              this.lexer.inline(token.text, token.tokens); // Queue this data to be processed for inline tokens
              return token;
            }
          },
          renderer(token) {
            return `<dl>${this.parser.parseInline(token.tokens)}\n</dl>`; // parseInline to turn child tokens into HTML
          },
        };
    
        const description = {
          name: "description",
          level: "inline", // Is this a block-level or inline-level tokenizer?
          start(src) {
            return src.match(/:/)?.index;
          }, // Hint to Marked.js to stop and check for a match
          tokenizer(src, tokens) {
            const rule = /^:([^:\n]+):([^:\n]*)(?:\n|$)/; // Regex for the complete token, anchor to string start
            const match = rule.exec(src);
            if (match) {
              return {
                // Token to generate
                type: "description", // Should match "name" above
                raw: match[0], // Text to consume from the source
                dt: this.lexer.inlineTokens(match[1].trim()), // Additional custom properties, including
                dd: this.lexer.inlineTokens(match[2].trim()), //   any further-nested inline tokens
              };
            }
          },
          renderer(token) {
            return `\n<dt>${this.parser.parseInline(
              token.dt
            )}</dt><dd>${this.parser.parseInline(token.dd)}</dd>`;
          },
          childTokens: ["dt", "dd"], // Any child tokens to be visited by walkTokens
        };
    
        function walkTokens(token) {
          // Post-processing on the completed token tree
          if (token.type === "strong") {
            token.text += " walked";
            token.tokens = this.Lexer.lexInline(token.text);
          }
        }
        marked.use({
          extensions: [descriptionList, description],
          walkTokens,
        });
    
        // EQUIVALENT TO:
    
        marked.use({ extensions: [descriptionList] });
        marked.use({ extensions: [description] });
        marked.use({ walkTokens });
        return marked;
      },
    };
  • write in README.md file

    A Description List:
    : Topic 1 : Description 1
    : **Topic 2** : _Description 2_
    
  • open chrome to debug

What is current behaviour

  • extension does not work

    The output of the browser is as follows:

    <p>
      A Description List: : Topic 1 : Description 1 : <strong>Topic 2</strong> :
      <em>Description 2</em>
    </p>

What is the expected behaviour

  • marked documentation says that the output will contain elements <dt> and <dd>

    <p>A Description List:</p>
    <dl>
      <dt>Topic 1</dt>
      <dd>Description 1</dd>
      <dt><strong>Topic 2 walked</strong></dt>
      <dd><em>Description 2</em></dd>
    </dl>

Other relevant information

  • Bug does still occur when all/other plugins are disabled?

  • Your OS:

  • Node.js version:

  • npm/yarn version:

  • Browser version:

  • Docsify version:

  • Docsify plugins:

Please create a reproducible sandbox

Edit 307qqv236

Mention the docsify version in which this bug was not present (if any)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions