"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var extension_manager_exports = {};
__export(extension_manager_exports, {
  ExtensionManager: () => ExtensionManager
});
module.exports = __toCommonJS(extension_manager_exports);
var import_keymap = require("./../pm/keymap.js");
var import_get_attributes_from_extensions = require("./helpers/get-attributes-from-extensions.js");
var import_get_extension_field = require("./helpers/get-extension-field.js");
var import_get_node_type = require("./helpers/get-node-type.js");
var import_get_rendered_attributes = require("./helpers/get-rendered-attributes.js");
var import_get_schema_by_resolved_extensions = require("./helpers/get-schema-by-resolved-extensions.js");
var import_get_schema_type_by_name = require("./helpers/get-schema-type-by-name.js");
var import_is_extension_rules_enabled = require("./helpers/is-extension-rules-enabled.js");
var import_split_extensions = require("./helpers/split-extensions.js");
var import_input_rule = require("./input-rule.js");
var import_mark = require("./mark.js");
var import_paste_rule = require("./paste-rule.js");
var import_call_or_return = require("./utilities/call-or-return.js");
var import_find_duplicates = require("./utilities/find-duplicates.js");
class ExtensionManager {
  constructor(extensions, editor) {
    this.splittableMarks = [];
    this.editor = editor;
    this.extensions = ExtensionManager.resolve(extensions);
    this.schema = (0, import_get_schema_by_resolved_extensions.getSchemaByResolvedExtensions)(this.extensions, editor);
    this.setupExtensions();
  }
  /**
   * Returns a flattened and sorted extension list while
   * also checking for duplicated extensions and warns the user.
   * @param extensions An array of Tiptap extensions
   * @returns An flattened and sorted array of Tiptap extensions
   */
  static resolve(extensions) {
    const resolvedExtensions = ExtensionManager.sort(ExtensionManager.flatten(extensions));
    const duplicatedNames = (0, import_find_duplicates.findDuplicates)(resolvedExtensions.map((extension) => extension.name));
    if (duplicatedNames.length) {
      console.warn(
        `[tiptap warn]: Duplicate extension names found: [${duplicatedNames.map((item) => `'${item}'`).join(", ")}]. This can lead to issues.`
      );
    }
    return resolvedExtensions;
  }
  /**
   * Create a flattened array of extensions by traversing the `addExtensions` field.
   * @param extensions An array of Tiptap extensions
   * @returns A flattened array of Tiptap extensions
   */
  static flatten(extensions) {
    return extensions.map((extension) => {
      const context = {
        name: extension.name,
        options: extension.options,
        storage: extension.storage
      };
      const addExtensions = (0, import_get_extension_field.getExtensionField)(
        extension,
        "addExtensions",
        context
      );
      if (addExtensions) {
        return [extension, ...this.flatten(addExtensions())];
      }
      return extension;
    }).flat(10);
  }
  /**
   * Sort extensions by priority.
   * @param extensions An array of Tiptap extensions
   * @returns A sorted array of Tiptap extensions by priority
   */
  static sort(extensions) {
    const defaultPriority = 100;
    return extensions.sort((a, b) => {
      const priorityA = (0, import_get_extension_field.getExtensionField)(a, "priority") || defaultPriority;
      const priorityB = (0, import_get_extension_field.getExtensionField)(b, "priority") || defaultPriority;
      if (priorityA > priorityB) {
        return -1;
      }
      if (priorityA < priorityB) {
        return 1;
      }
      return 0;
    });
  }
  /**
   * Get all commands from the extensions.
   * @returns An object with all commands where the key is the command name and the value is the command function
   */
  get commands() {
    return this.extensions.reduce((commands, extension) => {
      const context = {
        name: extension.name,
        options: extension.options,
        storage: extension.storage,
        editor: this.editor,
        type: (0, import_get_schema_type_by_name.getSchemaTypeByName)(extension.name, this.schema)
      };
      const addCommands = (0, import_get_extension_field.getExtensionField)(
        extension,
        "addCommands",
        context
      );
      if (!addCommands) {
        return commands;
      }
      return {
        ...commands,
        ...addCommands()
      };
    }, {});
  }
  /**
   * Get all registered Prosemirror plugins from the extensions.
   * @returns An array of Prosemirror plugins
   */
  get plugins() {
    const { editor } = this;
    const extensions = ExtensionManager.sort([...this.extensions].reverse());
    const inputRules = [];
    const pasteRules = [];
    const allPlugins = extensions.map((extension) => {
      const context = {
        name: extension.name,
        options: extension.options,
        storage: extension.storage,
        editor,
        type: (0, import_get_schema_type_by_name.getSchemaTypeByName)(extension.name, this.schema)
      };
      const plugins = [];
      const addKeyboardShortcuts = (0, import_get_extension_field.getExtensionField)(
        extension,
        "addKeyboardShortcuts",
        context
      );
      let defaultBindings = {};
      if (extension.type === "mark" && (0, import_get_extension_field.getExtensionField)(extension, "exitable", context)) {
        defaultBindings.ArrowRight = () => import_mark.Mark.handleExit({ editor, mark: extension });
      }
      if (addKeyboardShortcuts) {
        const bindings = Object.fromEntries(
          Object.entries(addKeyboardShortcuts()).map(([shortcut, method]) => {
            return [shortcut, () => method({ editor })];
          })
        );
        defaultBindings = { ...defaultBindings, ...bindings };
      }
      const keyMapPlugin = (0, import_keymap.keymap)(defaultBindings);
      plugins.push(keyMapPlugin);
      const addInputRules = (0, import_get_extension_field.getExtensionField)(
        extension,
        "addInputRules",
        context
      );
      if ((0, import_is_extension_rules_enabled.isExtensionRulesEnabled)(extension, editor.options.enableInputRules) && addInputRules) {
        inputRules.push(...addInputRules());
      }
      const addPasteRules = (0, import_get_extension_field.getExtensionField)(
        extension,
        "addPasteRules",
        context
      );
      if ((0, import_is_extension_rules_enabled.isExtensionRulesEnabled)(extension, editor.options.enablePasteRules) && addPasteRules) {
        pasteRules.push(...addPasteRules());
      }
      const addProseMirrorPlugins = (0, import_get_extension_field.getExtensionField)(
        extension,
        "addProseMirrorPlugins",
        context
      );
      if (addProseMirrorPlugins) {
        const proseMirrorPlugins = addProseMirrorPlugins();
        plugins.push(...proseMirrorPlugins);
      }
      return plugins;
    }).flat();
    return [
      (0, import_input_rule.inputRulesPlugin)({
        editor,
        rules: inputRules
      }),
      ...(0, import_paste_rule.pasteRulesPlugin)({
        editor,
        rules: pasteRules
      }),
      ...allPlugins
    ];
  }
  /**
   * Get all attributes from the extensions.
   * @returns An array of attributes
   */
  get attributes() {
    return (0, import_get_attributes_from_extensions.getAttributesFromExtensions)(this.extensions);
  }
  /**
   * Get all node views from the extensions.
   * @returns An object with all node views where the key is the node name and the value is the node view function
   */
  get nodeViews() {
    const { editor } = this;
    const { nodeExtensions } = (0, import_split_extensions.splitExtensions)(this.extensions);
    return Object.fromEntries(
      nodeExtensions.filter((extension) => !!(0, import_get_extension_field.getExtensionField)(extension, "addNodeView")).map((extension) => {
        const extensionAttributes = this.attributes.filter(
          (attribute) => attribute.type === extension.name
        );
        const context = {
          name: extension.name,
          options: extension.options,
          storage: extension.storage,
          editor,
          type: (0, import_get_node_type.getNodeType)(extension.name, this.schema)
        };
        const addNodeView = (0, import_get_extension_field.getExtensionField)(
          extension,
          "addNodeView",
          context
        );
        if (!addNodeView) {
          return [];
        }
        const nodeview = (node, view, getPos, decorations, innerDecorations) => {
          const HTMLAttributes = (0, import_get_rendered_attributes.getRenderedAttributes)(node, extensionAttributes);
          return addNodeView()({
            // pass-through
            node,
            view,
            getPos,
            decorations,
            innerDecorations,
            // tiptap-specific
            editor,
            extension,
            HTMLAttributes
          });
        };
        return [extension.name, nodeview];
      })
    );
  }
  /**
   * Go through all extensions, create extension storages & setup marks
   * & bind editor event listener.
   */
  setupExtensions() {
    this.extensions.forEach((extension) => {
      this.editor.extensionStorage[extension.name] = extension.storage;
      const context = {
        name: extension.name,
        options: extension.options,
        storage: extension.storage,
        editor: this.editor,
        type: (0, import_get_schema_type_by_name.getSchemaTypeByName)(extension.name, this.schema)
      };
      if (extension.type === "mark") {
        const keepOnSplit = (0, import_call_or_return.callOrReturn)((0, import_get_extension_field.getExtensionField)(extension, "keepOnSplit", context)) ?? true;
        if (keepOnSplit) {
          this.splittableMarks.push(extension.name);
        }
      }
      const onBeforeCreate = (0, import_get_extension_field.getExtensionField)(
        extension,
        "onBeforeCreate",
        context
      );
      const onCreate = (0, import_get_extension_field.getExtensionField)(extension, "onCreate", context);
      const onUpdate = (0, import_get_extension_field.getExtensionField)(extension, "onUpdate", context);
      const onSelectionUpdate = (0, import_get_extension_field.getExtensionField)(
        extension,
        "onSelectionUpdate",
        context
      );
      const onTransaction = (0, import_get_extension_field.getExtensionField)(
        extension,
        "onTransaction",
        context
      );
      const onFocus = (0, import_get_extension_field.getExtensionField)(extension, "onFocus", context);
      const onBlur = (0, import_get_extension_field.getExtensionField)(extension, "onBlur", context);
      const onDestroy = (0, import_get_extension_field.getExtensionField)(extension, "onDestroy", context);
      if (onBeforeCreate) {
        this.editor.on("beforeCreate", onBeforeCreate);
      }
      if (onCreate) {
        this.editor.on("create", onCreate);
      }
      if (onUpdate) {
        this.editor.on("update", onUpdate);
      }
      if (onSelectionUpdate) {
        this.editor.on("selectionUpdate", onSelectionUpdate);
      }
      if (onTransaction) {
        this.editor.on("transaction", onTransaction);
      }
      if (onFocus) {
        this.editor.on("focus", onFocus);
      }
      if (onBlur) {
        this.editor.on("blur", onBlur);
      }
      if (onDestroy) {
        this.editor.on("destroy", onDestroy);
      }
    });
  }
}
//# sourceMappingURL=extension-manager.js.map
