text: "use strict";
  
  /**
   * @module renderer
   */
  
  const path = require("path");
  const {File} = require("./types");
  const {isFunction} = require("./utils");
  
  /**
   * @description File renderer.
   */
  class Renderer {
    /**
     * @param {Logger} logger
     * @param {String[]} [skipRenderList] File that won't be rendered.
     * @return {Renderer}
     */
    constructor(logger, skipRenderList = []) {
      this.logger = logger;
      this._ = {};
      this.skipRenderList = skipRenderList;
    }
  
    /**
     * @callback renderCallback
     * @param {File} input
     * @return {File}
     */
    /**
     * @description Register a renderer function.
     * @param {String} srcExt Source file's extend name starts with `.`.
     * @param {String} [docExt=null] Doc file's extend name starts with `.`.
     * @param {renderCallback} fn
     */
    register(srcExt, docExt, fn) {
      if (isFunction(docExt) && fn == null) {
        // This renderer does not change extname.
        fn = docExt;
        docExt = srcExt;
      } else if (!isFunction(fn)) {
        throw new TypeError("fn must be a Function");
      }
      if (this._[srcExt] == null) {
        this._[srcExt] = {};
      }
      // Use another object for docExt,
      // so renderer for the same src and doc in plugin
      // can replace internal renderer.
      this._[srcExt][docExt] = {srcExt, docExt, fn};
    }
  
    /**
     * @description Render file with renderer function.
     * @param {File} input
     * @return {File} Rendered file.
     */
    async render(input) {
      const srcExt = path.extname(input["srcPath"]);
      const results = [];
      // It might be OK to allow renderer for binary file, but why?
      // It has no `raw`, `text` and why you want to handle binary with a SSG?
      // So better to just skip binary here.
      if (
        this._[srcExt] != null && !input["binary"] &&
        !this.skipRenderList.includes(input["srcPath"])
      ) {
        for (const handler of Object.values(this._[srcExt])) {
          const output = new File(input);
          const docExt = handler["docExt"];
          if (docExt !== srcExt) {
            const dirname = path.dirname(output["srcPath"]);
            const basename = path.basename(output["srcPath"], srcExt);
            output["docPath"] = path.join(dirname, `${basename}${docExt}`);
            this.logger.debug(`Hikaru is rendering \`${
              this.logger.cyan(output["srcPath"])
            }\` to \`${
              this.logger.cyan(output["docPath"])
            }\`...`);
          } else {
            output["docPath"] = output["srcPath"];
            this.logger.debug(`Hikaru is rendering \`${
              this.logger.cyan(output["srcPath"])
            }\`...`);
          }
          results.push(await handler["fn"](output));
        }
      } else {
        const output = new File(input);
        output["docPath"] = output["srcPath"];
        // this.logger.debug(`Hikaru is rendering \`${
        //   this.logger.cyan(output['srcPath'])
        // }\`...`)
        // For binary files, this is useless,
        // but we have to keep this line for other text files without renderer.
        output["content"] = output["text"];
        results.push(output);
      }
      return results;
    }
  }
  
  module.exports = Renderer;
  