/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/

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);

// main.ts
var main_exports = {};
__export(main_exports, {
  default: () => SpellcheckTogglerPlugin
});
module.exports = __toCommonJS(main_exports);

// src/plugin.ts
var import_obsidian2 = require("obsidian");

// src/settings.ts
var import_obsidian = require("obsidian");
var SpellcheckBehaviourOptionDisplay = {
  ["default" /* DEFAULT */]: "Always spellcheck",
  ["frontmatter" /* FRONTMATTER */]: "Use frontmatter",
  ["global" /* GLOBAL */]: "Never spellcheck"
};
var defaultSettings = {
  externalLinks: { behaviour: "global" /* GLOBAL */ },
  internalLinks: { behaviour: "global" /* GLOBAL */ },
  bareLinks: { behaviour: "global" /* GLOBAL */ },
  htmlComments: { behaviour: "default" /* DEFAULT */ },
  anyNode: { behaviour: "default" /* DEFAULT */ },
  emphasis: { behaviour: "default" /* DEFAULT */ },
  strong: { behaviour: "default" /* DEFAULT */ },
  blockquote: { behaviour: "default" /* DEFAULT */ }
};
var SpellcheckTogglerSettingTab = class extends import_obsidian.PluginSettingTab {
  constructor(app, plugin) {
    super(app, plugin);
    this.plugin = plugin;
  }
  display() {
    let { containerEl } = this;
    containerEl.empty();
    const createSpellcheckOptionDisplay = (optionKey, name, description, targetFormat) => {
      const settingContainer = containerEl.createDiv({
        cls: "settings-container"
      });
      const headingSetting = new import_obsidian.Setting(settingContainer).setHeading().setName(name).setDesc(description);
      if (targetFormat) {
        const span = headingSetting.controlEl.createEl("span", {
          text: `Targeted format: `,
          cls: "setting-item-target-label"
        });
        span.createEl("code", {
          text: targetFormat,
          cls: "setting-item-target-label"
        });
      }
      const frontmatterDrawer = settingContainer.createDiv({
        cls: "frontmatter-drawer"
      });
      new import_obsidian.Setting(frontmatterDrawer).setName("Frontmatter override property").setDesc(
        "Define the (boolean) frontmatter property which controls the spellcheck behaviour for a file."
      ).addText(
        (text) => {
          var _a;
          return text.setValue(
            (_a = this.plugin.settings[optionKey].frontmatterOverride) != null ? _a : ""
          ).onChange(
            (frontmatterOverride) => this.plugin.saveSettings({
              [optionKey]: {
                ...this.plugin.settings[optionKey],
                frontmatterOverride: frontmatterOverride.length ? frontmatterOverride : void 0
              }
            })
          );
        }
      );
      new import_obsidian.Setting(frontmatterDrawer).setName("Fallback behavior").setDesc(
        "Select the spellcheck fallback behavior for the node in files where the frontmatter property is absent."
      ).addDropdown((dropdown) => {
        var _a;
        const { frontmatter, ...filteredOptions } = SpellcheckBehaviourOptionDisplay;
        dropdown.addOptions({ ...filteredOptions }).onChange((frontmatterFallback) => {
          this.plugin.saveSettings({
            [optionKey]: {
              ...this.plugin.settings[optionKey],
              frontmatterFallback
            }
          });
        }).setValue(
          (_a = this.plugin.settings[optionKey].frontmatterFallback) != null ? _a : "default" /* DEFAULT */
        );
      });
      frontmatterDrawer.toggleClass(
        "hidden",
        [
          "default" /* DEFAULT */,
          "global" /* GLOBAL */
        ].includes(this.plugin.settings[optionKey].behaviour)
      );
      new import_obsidian.Setting(settingContainer).setName("Spellchecking behaviour").addDropdown(
        (dropdown) => dropdown.addOptions(SpellcheckBehaviourOptionDisplay).onChange((behaviour) => {
          this.plugin.saveSettings({
            [optionKey]: {
              ...this.plugin.settings[optionKey],
              behaviour
            }
          });
          frontmatterDrawer.toggleClass(
            "hidden",
            [
              "default" /* DEFAULT */,
              "global" /* GLOBAL */
            ].includes(
              this.plugin.settings[optionKey].behaviour
            )
          );
        }).setValue(this.plugin.settings[optionKey].behaviour)
      );
      settingContainer.appendChild(frontmatterDrawer);
    };
    const legendContainer = containerEl.createDiv({
      cls: "settings-container"
    });
    new import_obsidian.Setting(legendContainer).setHeading().setName("Spellcheck toggler settings").setDesc(
      "Configure spellchecking options. The behaviour of a spellcheck option is defined as follows:"
    );
    const list = legendContainer.createEl("ul");
    list.createEl("li", {
      text: `     "Always spellcheck": the editor default behaviour will be applied (the plugin is not active for the option).`,
      cls: "setting-item-target-label"
    });
    list.createEl("li", {
      text: `     "Use frontmatter": use the defined frontmatter property to toggle spellchecking per file.`,
      cls: "setting-item-target-label"
    });
    list.createEl("li", {
      text: `     "Never spellcheck": do not use spellcheck in any file for the option.`,
      cls: "setting-item-target-label"
    });
    createSpellcheckOptionDisplay(
      "externalLinks",
      "Markdown links option",
      "Toggle spellcheck underline for link text in any markdown link.",
      "![text](link)"
    );
    createSpellcheckOptionDisplay(
      "internalLinks",
      "Wikilinks option",
      "Toggle spellcheck underline for link text in any wikilink.",
      "[[ link text ]]"
    );
    createSpellcheckOptionDisplay(
      "bareLinks",
      "Bare links option",
      "Toggle spellcheck underline for text in any bare link.",
      "[text]"
    );
    createSpellcheckOptionDisplay(
      "htmlComments",
      "Html comment option",
      "Toggle spellcheck underline for any text inside an html comment block.",
      "<-- text -->"
    );
    createSpellcheckOptionDisplay(
      "blockquote",
      "Blockquote node option",
      "Toggle spellcheck for text inside block quotes.",
      ">text"
    );
    createSpellcheckOptionDisplay(
      "emphasis",
      "Italics (emphasis) node option",
      "Toggle spellcheck for italics (emphasis) text.",
      "*text*"
    );
    createSpellcheckOptionDisplay(
      "strong",
      "Bolded (strong) node option",
      "Toggle spellcheck for bolded (strong) text.",
      "**text**"
    );
    createSpellcheckOptionDisplay(
      "anyNode",
      "Per file option",
      'Toggle spellcheck for an entire file. With "Never spellcheck", spellchecking is disabled for all files.',
      "*"
    );
  }
};

// src/spellchecks/html-comments.ts
var import_view2 = require("@codemirror/view");

// src/spellchecks/apply-spellcheck-plugin.ts
var import_view = require("@codemirror/view");
var import_state = require("@codemirror/state");
var import_language = require("@codemirror/language");

// src/context.ts
var spellcheckContext = {
  file: null,
  frontmatter: null,
  settings: defaultSettings,
  uniqueOverrideKeys: []
};
var updateSpellcheckContext = (partialContext) => {
  if ("frontmatter" in partialContext) {
    updateFrontmatterWithDifference(partialContext.frontmatter);
    delete partialContext["frontmatter"];
  }
  if ("settings" in partialContext) {
    spellcheckContext.uniqueOverrideKeys = Object.values(
      partialContext.settings
    ).reduce((set, option) => {
      const override = option.frontmatterOverride;
      if (override !== void 0)
        set.push(override);
      return set;
    }, []);
  }
  spellcheckContext = { ...spellcheckContext, ...partialContext };
};
var updateFrontmatterWithDifference = (frontmatter) => {
  if (frontmatter === null) {
    spellcheckContext.frontmatter = null;
    return true;
  }
  const frontmatterSpellcheckKeys = Object.keys(frontmatter).filter(
    (k) => spellcheckContext.uniqueOverrideKeys.includes(k)
  );
  const filteredFrontmatter = frontmatterSpellcheckKeys.reduce((ffm, k) => {
    ffm[k] = frontmatter[k];
    return ffm;
  }, {});
  if (spellcheckContext.frontmatter === null || Object.keys(spellcheckContext.frontmatter).length !== frontmatterSpellcheckKeys.length) {
    spellcheckContext.frontmatter = filteredFrontmatter;
    return true;
  }
  for (const key of frontmatterSpellcheckKeys) {
    if (key in spellcheckContext.frontmatter && spellcheckContext.frontmatter[key] === frontmatter[key])
      continue;
    spellcheckContext.frontmatter = filteredFrontmatter;
    return true;
  }
  return false;
};
var getSpellcheckContextProperty = (key) => spellcheckContext[key];

// src/spellchecks/apply-spellcheck-plugin.ts
var ApplySpellcheckAttributePluginValue = class {
  constructor(view) {
    this.decorations = this.buildDecorations(view);
  }
  update(update) {
    if (!update.docChanged && !update.viewportChanged)
      return;
    this.decorations = this.buildDecorations(update.view);
  }
  buildDecorations(view) {
    const builder = new import_state.RangeSetBuilder();
    const markSpellcheckFalse = import_view.Decoration.mark({
      attributes: { spellcheck: "false" }
    });
    const adds = [];
    const enter = (node) => {
      var _a;
      if ((_a = this.isNodeEligible) == null ? void 0 : _a.call(this, node))
        adds.push({ from: node.from, to: node.to });
    };
    for (let { from, to } of view.visibleRanges)
      (0, import_language.syntaxTree)(view.state).iterate({
        from,
        to,
        enter
      });
    adds.sort((a, b) => a.from - b.from);
    for (const { from, to } of adds)
      builder.add(from, to, markSpellcheckFalse);
    return builder.finish();
  }
};
var checkNodeEligibility = (settingsKey) => {
  const frontmatter = getSpellcheckContextProperty("frontmatter");
  switch (getSpellcheckContextProperty("settings")[settingsKey].behaviour) {
    case "default" /* DEFAULT */:
      return false;
    case "global" /* GLOBAL */:
      return true;
    case "frontmatter" /* FRONTMATTER */:
      const override = getSpellcheckContextProperty("settings")[settingsKey].frontmatterOverride;
      const isOverrideInFrontmatter = frontmatter !== null && override !== void 0 && override in frontmatter;
      const fallback = getSpellcheckContextProperty("settings")[settingsKey].frontmatterFallback;
      const isOverrideFalse = isOverrideInFrontmatter && frontmatter[override] === false;
      const isFallbackDisable = !isOverrideInFrontmatter && fallback === "global" /* GLOBAL */;
      return isOverrideFalse || isFallbackDisable;
  }
  return false;
};

// src/spellchecks/html-comments.ts
var HtmlCommentSpellcheckPluginValue = class extends ApplySpellcheckAttributePluginValue {
  isNodeEligible(node) {
    if (!node.type.name.startsWith("comment"))
      return false;
    return checkNodeEligibility("htmlComments");
  }
};
var htmlCommentSpellcheckPluginValue = import_view2.ViewPlugin.fromClass(
  HtmlCommentSpellcheckPluginValue,
  {
    decorations: (pluginValue) => pluginValue.decorations
  }
);

// src/spellchecks/markdown-links.ts
var import_view3 = require("@codemirror/view");
var MarkdownLinkSpellcheckPluginValue = class extends ApplySpellcheckAttributePluginValue {
  isNodeEligible(node) {
    if (node.type.name.match(/^link|.*_link$/) === null || node.type.name.contains("hmd-barelink"))
      return false;
    return checkNodeEligibility("externalLinks");
  }
};
var markdownLinkSpellcheckViewPlugin = import_view3.ViewPlugin.fromClass(
  MarkdownLinkSpellcheckPluginValue,
  {
    decorations: (pluginValue) => pluginValue.decorations
  }
);

// src/spellchecks/wiki-links.ts
var import_view4 = require("@codemirror/view");
var WikiLinkSpellcheckPluginValue = class extends ApplySpellcheckAttributePluginValue {
  isNodeEligible(node) {
    if (!node.type.name.contains("hmd-internal-link"))
      return false;
    return checkNodeEligibility("internalLinks");
  }
};
var wikiLinkSpellcheckViewPlugin = import_view4.ViewPlugin.fromClass(
  WikiLinkSpellcheckPluginValue,
  {
    decorations: (pluginValue) => pluginValue.decorations
  }
);

// src/spellchecks/emphasis.ts
var import_view5 = require("@codemirror/view");
var EmphasisSpellcheckPluginValue = class extends ApplySpellcheckAttributePluginValue {
  isNodeEligible(node) {
    if (!node.type.name.startsWith("em"))
      return false;
    return checkNodeEligibility("emphasis");
  }
};
var emphasisSpellcheckPluginValue = import_view5.ViewPlugin.fromClass(
  EmphasisSpellcheckPluginValue,
  {
    decorations: (pluginValue) => pluginValue.decorations
  }
);

// src/spellchecks/strong.ts
var import_view6 = require("@codemirror/view");
var StrongSpellcheckPluginValue = class extends ApplySpellcheckAttributePluginValue {
  isNodeEligible(node) {
    if (!node.type.name.startsWith("strong"))
      return false;
    return checkNodeEligibility("strong");
  }
};
var strongSpellcheckPluginValue = import_view6.ViewPlugin.fromClass(
  StrongSpellcheckPluginValue,
  {
    decorations: (pluginValue) => pluginValue.decorations
  }
);

// src/migration/index.ts
var validateAndMigrateSettings = (settings) => {
  if (settings === null)
    return {};
  const keys1_1_0ToKeys1_2_0 = {
    spellcheckExternalLinks: "externalLinks",
    spellcheckInternalLinks: "internalLinks",
    spellcheckHtmlComments: "htmlComments"
  };
  for (const [srcKey, destKey] of Object.entries(keys1_1_0ToKeys1_2_0)) {
    if (srcKey in settings && typeof settings[srcKey] === "boolean") {
      settings[destKey] = {
        behaviour: settings[srcKey] ? "default" /* DEFAULT */ : "global" /* GLOBAL */
      };
      delete settings[srcKey];
    }
  }
  for (const [spellcheckKey, spellcheckOption] of Object.entries(settings)) {
    const behaviour = spellcheckOption["behaviour"];
    if (["opt-in", "opt-out"].includes(behaviour)) {
      settings[spellcheckKey] = {
        behaviour: "frontmatter" /* FRONTMATTER */,
        frontmatterOverride: spellcheckOption["frontmatterOverride"],
        frontmatterFallback: behaviour === "opt-in" ? "default" /* DEFAULT */ : "global" /* GLOBAL */
      };
    }
  }
  return { ...settings };
};

// src/spellchecks/blockquote.ts
var import_view7 = require("@codemirror/view");
var BlockQuoteSpellcheckPluginValue = class extends ApplySpellcheckAttributePluginValue {
  isNodeEligible(node) {
    if (!node.type.name.startsWith("quote"))
      return false;
    return checkNodeEligibility("blockquote");
  }
};
var blockQuoteSpellcheckPluginValue = import_view7.ViewPlugin.fromClass(
  BlockQuoteSpellcheckPluginValue,
  {
    decorations: (pluginValue) => pluginValue.decorations
  }
);

// src/spellchecks/barelink.ts
var import_view8 = require("@codemirror/view");
var BareLinkSpellcheckPluginValue = class extends ApplySpellcheckAttributePluginValue {
  isNodeEligible(node) {
    if (!node.type.name.contains("hmd-barelink_link"))
      return false;
    return checkNodeEligibility("bareLinks");
  }
};
var bareLinkSpellcheckPluginValue = import_view8.ViewPlugin.fromClass(
  BareLinkSpellcheckPluginValue,
  {
    decorations: (pluginValue) => pluginValue.decorations
  }
);

// src/plugin.ts
var SpellcheckTogglerPlugin = class extends import_obsidian2.Plugin {
  constructor() {
    super(...arguments);
    this.editorExtensions = [];
  }
  async loadSettings() {
    const userSettings = validateAndMigrateSettings(await this.loadData());
    this.settings = { ...defaultSettings, ...userSettings };
    this.saveData(this.settings);
    updateSpellcheckContext({ settings: this.settings });
  }
  async saveSettings(settings) {
    this.settings = { ...this.settings, ...settings };
    await this.saveData(this.settings);
    updateSpellcheckContext({ settings: this.settings });
    this.refreshExtensions();
  }
  buildExtensions() {
    this.editorExtensions.length = 0;
    if (this.settings.internalLinks.behaviour !== "default" /* DEFAULT */)
      this.editorExtensions.push(wikiLinkSpellcheckViewPlugin);
    if (this.settings.externalLinks.behaviour !== "default" /* DEFAULT */)
      this.editorExtensions.push(markdownLinkSpellcheckViewPlugin);
    if (this.settings.bareLinks.behaviour !== "default" /* DEFAULT */)
      this.editorExtensions.push(bareLinkSpellcheckPluginValue);
    if (this.settings.htmlComments.behaviour !== "default" /* DEFAULT */)
      this.editorExtensions.push(htmlCommentSpellcheckPluginValue);
    if (this.settings.blockquote.behaviour !== "default" /* DEFAULT */)
      this.editorExtensions.push(blockQuoteSpellcheckPluginValue);
    if (this.settings.emphasis.behaviour !== "default" /* DEFAULT */)
      this.editorExtensions.push(emphasisSpellcheckPluginValue);
    if (this.settings.strong.behaviour !== "default" /* DEFAULT */)
      this.editorExtensions.push(strongSpellcheckPluginValue);
  }
  refreshExtensions() {
    var _a, _b;
    this.buildExtensions();
    this.app.workspace.updateOptions();
    (_b = (_a = this.app.workspace.activeEditor) == null ? void 0 : _a.editor) == null ? void 0 : _b.refresh();
  }
  handleSpellcheckAttribute() {
    let globalSpellcheckFlag = true;
    const anyNodeOption = getSpellcheckContextProperty("settings")["anyNode"];
    switch (anyNodeOption.behaviour) {
      case "global" /* GLOBAL */:
        globalSpellcheckFlag = false;
        break;
      case "frontmatter" /* FRONTMATTER */:
        const frontmatter = getSpellcheckContextProperty("frontmatter");
        const isOverrideInFrontmatter = frontmatter !== null && anyNodeOption.frontmatterOverride !== void 0 && anyNodeOption.frontmatterOverride in frontmatter;
        const isOverrideTrue = isOverrideInFrontmatter && frontmatter[anyNodeOption.frontmatterOverride] === true;
        const isFallbackDefault = !isOverrideInFrontmatter && anyNodeOption.frontmatterFallback !== "global" /* GLOBAL */;
        globalSpellcheckFlag = isOverrideTrue || isFallbackDefault;
        break;
    }
    const content = this.app.workspace.containerEl.querySelector(".cm-content");
    const attributeObserver = new MutationObserver((_, observer) => {
      content.setAttribute("spellcheck", String(globalSpellcheckFlag));
      observer.disconnect();
    });
    content.setAttribute("spellcheck", String(globalSpellcheckFlag));
    attributeObserver.observe(content, {
      attributes: true,
      attributeOldValue: true,
      attributeFilter: ["spellcheck"]
    });
  }
  onFileOpen(file) {
    var _a;
    if (file === null)
      return;
    const metadata = this.app.metadataCache.getFileCache(file);
    const frontmatter = (_a = metadata == null ? void 0 : metadata.frontmatter) != null ? _a : null;
    updateSpellcheckContext({
      file,
      frontmatter
    });
    this.handleSpellcheckAttribute();
  }
  onFileModify(file) {
    var _a;
    if (file === null || ((_a = this.app.workspace.getActiveFile()) == null ? void 0 : _a.basename) !== file.basename)
      return;
    (async () => {
      var _a2;
      const content = await this.app.vault.cachedRead(file);
      const frontmatterInfo = (0, import_obsidian2.getFrontMatterInfo)(content);
      if (!frontmatterInfo.exists)
        return;
      const overrideKeys = getSpellcheckContextProperty("uniqueOverrideKeys");
      const frontmatter = {};
      for (const line of frontmatterInfo.frontmatter.split("\n")) {
        const [property, value] = line.split(":").map((s) => s.trim());
        if (value === void 0 || value.length === 0)
          continue;
        const parsedValue = value === "true" ? true : value === "false" ? false : void 0;
        if (parsedValue !== void 0 && overrideKeys.includes(property))
          frontmatter[property] = parsedValue;
      }
      const didDiffer = updateFrontmatterWithDifference(frontmatter);
      if (!didDiffer)
        return;
      this.handleSpellcheckAttribute();
      const editor = (_a2 = this.app.workspace.activeEditor) == null ? void 0 : _a2.editor;
      if (!editor)
        return;
      editor.refresh();
    })();
  }
  async onload() {
    await this.loadSettings();
    this.addSettingTab(new SpellcheckTogglerSettingTab(this.app, this));
    this.buildExtensions();
    this.registerEditorExtension(this.editorExtensions);
    this.onFileOpen(this.app.workspace.getActiveFile());
    this.onFileOpenEventRef = this.app.workspace.on(
      "file-open",
      this.onFileOpen.bind(this)
    );
    this.onFileModifyEventRef = this.app.vault.on(
      "modify",
      this.onFileModify.bind(this)
    );
  }
  unload() {
    this.app.workspace.offref(this.onFileOpenEventRef);
    this.app.vault.offref(this.onFileModifyEventRef);
    super.unload();
  }
};

/* nosourcemap */