text: "use strict";
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
      var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
      if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
      else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
      return c > 3 && r && Object.defineProperty(target, key, r), r;
  };
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.MarkedPlugin = void 0;
  const FS = require("fs-extra");
  const Path = require("path");
  const Marked = require("marked");
  const Handlebars = require("handlebars");
  const components_1 = require("../components");
  const events_1 = require("../events");
  const utils_1 = require("../../utils");
  const highlighter_1 = require("../../utils/highlighter");
  const customMarkedRenderer = new Marked.Renderer();
  customMarkedRenderer.heading = (text, level, _, slugger) => {
      const slug = slugger.slug(text);
      return `
  <a href="#${slug}" id="${slug}" style="color: inherit; text-decoration: none;">
    <h${level}>${text}</h${level}>
  </a>
  `;
  };
  /**
   * A plugin that exposes the markdown, compact and relativeURL helper to handlebars.
   *
   * Templates should parse all comments with the markdown handler so authors can
   * easily format their documentation. TypeDoc uses the Marked (https://github.com/markedjs/marked)
   * markdown parser and HighlightJS (https://github.com/isagalaev/highlight.js) to highlight
   * code blocks within markdown sections. Additionally this plugin allows to link to other symbols
   * using double angle brackets.
   *
   * You can use the markdown helper anywhere in the templates to convert content to html:
   *
   * ```handlebars
   * {{#markdown}}{{{comment.text}}}{{/markdown}}
   * ```
   *
   * The compact helper removes all newlines of its content:
   *
   * ```handlebars
   * {{#compact}}
   *   Compact
   *   this
   * {{/compact}}
   * ```
   *
   * The relativeURL helper simply transforms an absolute url into a relative url:
   *
   * ```handlebars
   * {{#relativeURL url}}
   * ```
   */
  let MarkedPlugin = class MarkedPlugin extends components_1.ContextAwareRendererComponent {
      constructor() {
          super(...arguments);
          /**
           * The pattern used to find references in markdown.
           */
          this.includePattern = /\[\[include:([^\]]+?)\]\]/g;
          /**
           * The pattern used to find media links.
           */
          this.mediaPattern = /media:\/\/([^ ")\]}]+)/g;
      }
      /**
       * Create a new MarkedPlugin instance.
       */
      initialize() {
          super.initialize();
          this.listenTo(this.owner, events_1.MarkdownEvent.PARSE, this.onParseMarkdown);
          // eslint-disable-next-line @typescript-eslint/no-this-alias
          const that = this;
          Handlebars.registerHelper("markdown", function (arg) {
              const root = arg.data.root;
              that.outputFileName = root.filename;
              that.sources = root.model.sources;
              return that.parseMarkdown(arg.fn(this), this);
          });
          Handlebars.registerHelper("relativeURL", (url) => url ? this.getRelativeUrl(url) : url);
      }
      /**
       * Highlight the syntax of the given text using HighlightJS.
       *
       * @param text  The text that should be highlighted.
       * @param lang  The language that should be used to highlight the string.
       * @return A html string with syntax highlighting.
       */
      getHighlighted(text, lang) {
          var _a;
          lang = lang || "typescript";
          lang = lang.toLowerCase();
          if (!highlighter_1.isSupportedLanguage(lang)) {
              // Extra newline because of the progress bar
              this.application.logger.warn(`
  Unsupported highlight language "${lang}" will not be highlighted. Run typedoc --help for a list of supported languages.
  target code block :
  \t${text.split("\n").join("\n\t")}
  source files :${(_a = this.sources) === null || _a === void 0 ? void 0 : _a.map((source) => `\n\t${source.fileName}`).join()}
  output file :
  \t${this.outputFileName}`);
              return text;
          }
          return highlighter_1.highlight(text, lang, this.theme);
      }
      /**
       * Parse the given markdown string and return the resulting html.
       *
       * @param text  The markdown string that should be parsed.
       * @param context  The current handlebars context.
       * @returns The resulting html string.
       */
      parseMarkdown(text, context) {
          if (this.includes) {
              text = text.replace(this.includePattern, (_match, path) => {
                  path = Path.join(this.includes, path.trim());
                  if (FS.existsSync(path) && FS.statSync(path).isFile()) {
                      const contents = utils_1.readFile(path);
                      if (path.substr(-4).toLocaleLowerCase() === ".hbs") {
                          const template = Handlebars.compile(contents);
                          return template(context, {
                              allowProtoMethodsByDefault: true,
                              allowProtoPropertiesByDefault: true,
                          });
                      }
                      else {
                          return contents;
                      }
                  }
                  else {
                      this.application.logger.warn("Could not find file to include: " + path);
                      return "";
                  }
              });
          }
          if (this.mediaDirectory) {
              text = text.replace(this.mediaPattern, (match, path) => {
                  const fileName = Path.join(this.mediaDirectory, path);
                  if (FS.existsSync(fileName) &&
                      FS.statSync(fileName).isFile()) {
                      return this.getRelativeUrl("media") + "/" + path;
                  }
                  else {
                      this.application.logger.warn("Could not find media file: " + fileName);
                      return match;
                  }
              });
          }
          const event = new events_1.MarkdownEvent(events_1.MarkdownEvent.PARSE, text, text);
          this.owner.trigger(event);
          return event.parsedText;
      }
      /**
       * Triggered before the renderer starts rendering a project.
       *
       * @param event  An event object describing the current render operation.
       */
      onBeginRenderer(event) {
          super.onBeginRenderer(event);
          Marked.setOptions(this.createMarkedOptions());
          delete this.includes;
          if (this.includeSource) {
              const includes = Path.resolve(this.includeSource);
              if (FS.existsSync(includes) &&
                  FS.statSync(includes).isDirectory()) {
                  this.includes = includes;
              }
              else {
                  this.application.logger.warn("Could not find provided includes directory: " + includes);
              }
          }
          if (this.mediaSource) {
              const media = Path.resolve(this.mediaSource);
              if (FS.existsSync(media) && FS.statSync(media).isDirectory()) {
                  this.mediaDirectory = Path.join(event.outputDirectory, "media");
                  FS.copySync(media, this.mediaDirectory);
              }
              else {
                  this.mediaDirectory = undefined;
                  this.application.logger.warn("Could not find provided media directory: " + media);
              }
          }
      }
      /**
       * Creates an object with options that are passed to the markdown parser.
       *
       * @returns The options object for the markdown parser.
       */
      createMarkedOptions() {
          var _a, _b, _c, _d;
          const markedOptions = ((_a = this.application.options.getValue("markedOptions")) !== null && _a !== void 0 ? _a : {});
          if (typeof markedOptions === "object" &&
              !Array.isArray(markedOptions)) {
              // Set some default values if they are not specified via the TypeDoc option
              (_b = markedOptions.highlight) !== null && _b !== void 0 ? _b : (markedOptions.highlight = (text, lang) => this.getHighlighted(text, lang));
              (_c = markedOptions.renderer) !== null && _c !== void 0 ? _c : (markedOptions.renderer = customMarkedRenderer);
              (_d = markedOptions.mangle) !== null && _d !== void 0 ? _d : (markedOptions.mangle = false); // See https://github.com/TypeStrong/typedoc/issues/1395
              return markedOptions;
          }
          throw new Error("The value provided via the 'markedOptions' option must be a non-array object.");
      }
      /**
       * Triggered when [[MarkedPlugin]] parses a markdown string.
       *
       * @param event
       */
      onParseMarkdown(event) {
          event.parsedText = Marked(event.parsedText);
      }
  };
  __decorate([
      utils_1.BindOption("includes")
  ], MarkedPlugin.prototype, "includeSource", void 0);
  __decorate([
      utils_1.BindOption("media")
  ], MarkedPlugin.prototype, "mediaSource", void 0);
  __decorate([
      utils_1.BindOption("highlightTheme")
  ], MarkedPlugin.prototype, "theme", void 0);
  MarkedPlugin = __decorate([
      components_1.Component({ name: "marked" })
  ], MarkedPlugin);
  exports.MarkedPlugin = MarkedPlugin;
  