"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.wrappingInputRule = exports.textblockTypeInputRule = void 0;
exports.hasCodeMark = hasCodeMark;
exports.markInputRule = markInputRule;
exports.nodeInputRule = nodeInputRule;
exports.inlineNodeInputRule = inlineNodeInputRule;
const prosemirror_inputrules_1 = require("prosemirror-inputrules");
const prosemirror_model_1 = require("prosemirror-model");
const prosemirror_state_1 = require("prosemirror-state");
const specs_1 = require("../extensions/markdown/specs.js");
const lodash_1 = require("../lodash.js");
const marks_1 = require("./marks.js");
// TODO: remove explicit import from code extension
function hasCodeMark(state, _match, start, end) {
    // TODO: remove explicit import from code extension
    const codeMarkType = (0, specs_1.codeType)(state.schema);
    if ((0, marks_1.isMarkActive)(state, codeMarkType))
        return true;
    if (state.doc.rangeHasMark(start, end, codeMarkType))
        return true;
    return false;
}
var rulebuilders_1 = require("./rulebuilders.js");
Object.defineProperty(exports, "textblockTypeInputRule", { enumerable: true, get: function () { return rulebuilders_1.textblockTypeInputRule; } });
Object.defineProperty(exports, "wrappingInputRule", { enumerable: true, get: function () { return rulebuilders_1.wrappingInputRule; } });
function getMarksBetween(start, end, state) {
    let marks = [];
    state.doc.nodesBetween(start, end, (node, pos) => {
        marks = [
            ...marks,
            ...node.marks.map((mark) => ({
                start: pos,
                end: pos + node.nodeSize,
                mark,
            })),
        ];
    });
    return marks;
}
function escapeRegex(string) {
    // eslint-disable-next-line no-useless-escape
    return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}
// TODO: link has a custom input rule handler, think about generalizing
function markInputRule(rule, markType, getAttrs) {
    let regexp;
    if (rule instanceof RegExp) {
        regexp = rule;
    }
    else {
        const open = escapeRegex(rule.open);
        const close = escapeRegex(rule.close);
        const ignoreBetween = escapeRegex(rule.ignoreBetween || '');
        regexp = new RegExp(`(?:${open})` +
            (ignoreBetween ? `([^\\s${ignoreBetween}]+)` : `([\\S]+)`) +
            `(?:${close})\\s$`);
    }
    return new prosemirror_inputrules_1.InputRule(regexp, (state, match, start, end) => {
        // handle the rule only if is start of line or there is a space before "open" symbols
        if (match.index > 0) {
            const re = match;
            if (re.input[re.index - 1] !== ' ')
                return null;
        }
        if (hasCodeMark(state, match, start, end))
            return null;
        const attrs = getAttrs instanceof Function ? getAttrs(match) : getAttrs;
        const { tr } = state;
        const m = match.length - 1;
        let markEnd = end;
        let markStart = start;
        if (match[m]) {
            const matchStart = start + match[0].indexOf(match[m - 1]);
            const matchEnd = matchStart + match[m - 1].length - 1;
            const textStart = matchStart + match[m - 1].lastIndexOf(match[m]);
            const textEnd = textStart + match[m].length;
            const marksBetween = getMarksBetween(start, end, state);
            const excludedMarks = marksBetween
                .filter((item) => item.mark.type.excludes(markType))
                .filter((item) => item.end > matchStart);
            if (excludedMarks.length) {
                return null;
            }
            if (textEnd < matchEnd) {
                tr.delete(textEnd, matchEnd);
            }
            if (textStart > matchStart) {
                tr.delete(matchStart, textStart);
            }
            markStart = matchStart;
            markEnd = markStart + match[m].length;
        }
        tr.addMark(markStart, markEnd, markType.create(attrs));
        tr.removeStoredMark(markType);
        return tr;
    });
}
function nodeInputRule(regexp, fragment, selectionOffset = 0) {
    return new prosemirror_inputrules_1.InputRule(regexp, (state, match, start, end) => {
        if (hasCodeMark(state, match, start, end))
            return null;
        const [matchStr] = match;
        const { tr } = state;
        if (matchStr) {
            tr.replaceWith(start - 1, end, (0, lodash_1.isFunction)(fragment)
                ? fragment(matchStr) ?? prosemirror_model_1.Fragment.empty
                : fragment ?? prosemirror_model_1.Fragment.empty).setSelection(new prosemirror_state_1.TextSelection(tr.doc.resolve(start + selectionOffset)));
        }
        return tr;
    });
}
function inlineNodeInputRule(regexp, fragment) {
    return new prosemirror_inputrules_1.InputRule(regexp, (state, match, start, end) => {
        if (hasCodeMark(state, match, start, end))
            return null;
        const [matchStr] = match;
        const { tr } = state;
        if (matchStr) {
            tr.replaceWith(start, end, fragment(matchStr) ?? prosemirror_model_1.Fragment.empty).setSelection(new prosemirror_state_1.TextSelection(tr.doc.resolve(end)));
        }
        return tr;
    });
}
//# sourceMappingURL=inputrules.js.map
