/**/, /**//
} -> /**/// ^-- not valid because ** doens't follow symlinks secondPhasePreProcess(globParts) { - for (let i = 0; i < globParts.length - 1; i++) { - for (let j = i + 1; j < globParts.length; j++) { - const matched = this.partsMatch(globParts[i], globParts[j], !this.preserveMultipleSlashes); + for (let i2 = 0; i2 < globParts.length - 1; i2++) { + for (let j2 = i2 + 1; j2 < globParts.length; j2++) { + const matched = this.partsMatch(globParts[i2], globParts[j2], !this.preserveMultipleSlashes); if (matched) { - globParts[i] = []; - globParts[j] = matched; + globParts[i2] = []; + globParts[j2] = matched; break; } } } return globParts.filter((gs) => gs.length); } - partsMatch(a, b, emptyGSMatch = false) { + partsMatch(a2, b2, emptyGSMatch = false) { let ai = 0; let bi = 0; let result = []; let which = ""; - while (ai < a.length && bi < b.length) { - if (a[ai] === b[bi]) { - result.push(which === "b" ? b[bi] : a[ai]); + while (ai < a2.length && bi < b2.length) { + if (a2[ai] === b2[bi]) { + result.push(which === "b" ? b2[bi] : a2[ai]); ai++; bi++; - } else if (emptyGSMatch && a[ai] === "**" && b[bi] === a[ai + 1]) { - result.push(a[ai]); + } else if (emptyGSMatch && a2[ai] === "**" && b2[bi] === a2[ai + 1]) { + result.push(a2[ai]); ai++; - } else if (emptyGSMatch && b[bi] === "**" && a[ai] === b[bi + 1]) { - result.push(b[bi]); + } else if (emptyGSMatch && b2[bi] === "**" && a2[ai] === b2[bi + 1]) { + result.push(b2[bi]); bi++; - } else if (a[ai] === "*" && b[bi] && (this.options.dot || !b[bi].startsWith(".")) && b[bi] !== "**") { + } else if (a2[ai] === "*" && b2[bi] && (this.options.dot || !b2[bi].startsWith(".")) && b2[bi] !== "**") { if (which === "b") return false; which = "a"; - result.push(a[ai]); + result.push(a2[ai]); ai++; bi++; - } else if (b[bi] === "*" && a[ai] && (this.options.dot || !a[ai].startsWith(".")) && a[ai] !== "**") { + } else if (b2[bi] === "*" && a2[ai] && (this.options.dot || !a2[ai].startsWith(".")) && a2[ai] !== "**") { if (which === "a") return false; which = "b"; - result.push(b[bi]); + result.push(b2[bi]); ai++; bi++; } else { return false; } } - return a.length === b.length && result; + return a2.length === b2.length && result; } parseNegate() { if (this.nonegate) @@ -10746,7 +9545,7 @@ var Minimatch = class { const pattern = this.pattern; let negate = false; let negateOffset = 0; - for (let i = 0; i < pattern.length && pattern.charAt(i) === "!"; i++) { + for (let i2 = 0; i2 < pattern.length && pattern.charAt(i2) === "!"; i2++) { negate = !negate; negateOffset++; } @@ -10760,7 +9559,7 @@ var Minimatch = class { // out of pattern, then that's fine, as long as all // the parts match. matchOne(file, pattern, partial = false) { - const options2 = this.options; + const options = this.options; if (this.isWindows) { const fileDrive = typeof file[0] === "string" && /^[a-z]:$/i.test(file[0]); const fileUNC = !fileDrive && file[0] === "" && file[1] === "" && file[2] === "?" && /^[a-z]:$/i.test(file[3]); @@ -10788,20 +9587,20 @@ var Minimatch = class { this.debug("matchOne", file.length, pattern.length); for (var fi = 0, pi = 0, fl = file.length, pl = pattern.length; fi < fl && pi < pl; fi++, pi++) { this.debug("matchOne loop"); - var p = pattern[pi]; - var f = file[fi]; - this.debug(pattern, p, f); - if (p === false) { + var p2 = pattern[pi]; + var f2 = file[fi]; + this.debug(pattern, p2, f2); + if (p2 === false) { return false; } - if (p === GLOBSTAR) { - this.debug("GLOBSTAR", [pattern, p, f]); + if (p2 === GLOBSTAR) { + this.debug("GLOBSTAR", [pattern, p2, f2]); var fr = fi; var pr = pi + 1; if (pr === pl) { this.debug("** at the end"); for (; fi < fl; fi++) { - if (file[fi] === "." || file[fi] === ".." || !options2.dot && file[fi].charAt(0) === ".") + if (file[fi] === "." || file[fi] === ".." || !options.dot && file[fi].charAt(0) === ".") return false; } return true; @@ -10813,7 +9612,7 @@ var Minimatch = class { this.debug("globstar found match!", fr, fl, swallowee); return true; } else { - if (swallowee === "." || swallowee === ".." || !options2.dot && swallowee.charAt(0) === ".") { + if (swallowee === "." || swallowee === ".." || !options.dot && swallowee.charAt(0) === ".") { this.debug("dot detected!", file, fr, pattern, pr); break; } @@ -10830,12 +9629,12 @@ var Minimatch = class { return false; } let hit; - if (typeof p === "string") { - hit = f === p; - this.debug("string match", p, f, hit); + if (typeof p2 === "string") { + hit = f2 === p2; + this.debug("string match", p2, f2, hit); } else { - hit = p.test(f); - this.debug("pattern match", p, f, hit); + hit = p2.test(f2); + this.debug("pattern match", p2, f2, hit); } if (!hit) return false; @@ -10855,22 +9654,22 @@ var Minimatch = class { } parse(pattern) { assertValidPattern(pattern); - const options2 = this.options; + const options = this.options; if (pattern === "**") return GLOBSTAR; if (pattern === "") return ""; - let m; + let m2; let fastTest = null; - if (m = pattern.match(starRE)) { - fastTest = options2.dot ? starTestDot : starTest; - } else if (m = pattern.match(starDotExtRE)) { - fastTest = (options2.nocase ? options2.dot ? starDotExtTestNocaseDot : starDotExtTestNocase : options2.dot ? starDotExtTestDot : starDotExtTest)(m[1]); - } else if (m = pattern.match(qmarksRE)) { - fastTest = (options2.nocase ? options2.dot ? qmarksTestNocaseDot : qmarksTestNocase : options2.dot ? qmarksTestDot : qmarksTest)(m); - } else if (m = pattern.match(starDotStarRE)) { - fastTest = options2.dot ? starDotStarTestDot : starDotStarTest; - } else if (m = pattern.match(dotStarRE)) { + if (m2 = pattern.match(starRE)) { + fastTest = options.dot ? starTestDot : starTest; + } else if (m2 = pattern.match(starDotExtRE)) { + fastTest = (options.nocase ? options.dot ? starDotExtTestNocaseDot : starDotExtTestNocase : options.dot ? starDotExtTestDot : starDotExtTest)(m2[1]); + } else if (m2 = pattern.match(qmarksRE)) { + fastTest = (options.nocase ? options.dot ? qmarksTestNocaseDot : qmarksTestNocase : options.dot ? qmarksTestDot : qmarksTest)(m2); + } else if (m2 = pattern.match(starDotStarRE)) { + fastTest = options.dot ? starDotStarTestDot : starDotStarTest; + } else if (m2 = pattern.match(dotStarRE)) { fastTest = dotStarTest; } const re = AST.fromGlob(pattern, this.options).toMMPattern(); @@ -10887,37 +9686,37 @@ var Minimatch = class { this.regexp = false; return this.regexp; } - const options2 = this.options; - const twoStar = options2.noglobstar ? star2 : options2.dot ? twoStarDot : twoStarNoDot; - const flags = new Set(options2.nocase ? ["i"] : []); + const options = this.options; + const twoStar = options.noglobstar ? star2 : options.dot ? twoStarDot : twoStarNoDot; + const flags = new Set(options.nocase ? ["i"] : []); let re = set2.map((pattern) => { - const pp = pattern.map((p) => { - if (p instanceof RegExp) { - for (const f of p.flags.split("")) - flags.add(f); + const pp = pattern.map((p2) => { + if (p2 instanceof RegExp) { + for (const f2 of p2.flags.split("")) + flags.add(f2); } - return typeof p === "string" ? regExpEscape2(p) : p === GLOBSTAR ? GLOBSTAR : p._src; + return typeof p2 === "string" ? regExpEscape2(p2) : p2 === GLOBSTAR ? GLOBSTAR : p2._src; }); - pp.forEach((p, i) => { - const next = pp[i + 1]; - const prev = pp[i - 1]; - if (p !== GLOBSTAR || prev === GLOBSTAR) { + pp.forEach((p2, i2) => { + const next = pp[i2 + 1]; + const prev = pp[i2 - 1]; + if (p2 !== GLOBSTAR || prev === GLOBSTAR) { return; } if (prev === void 0) { if (next !== void 0 && next !== GLOBSTAR) { - pp[i + 1] = "(?:\\/|" + twoStar + "\\/)?" + next; + pp[i2 + 1] = "(?:\\/|" + twoStar + "\\/)?" + next; } else { - pp[i] = twoStar; + pp[i2] = twoStar; } } else if (next === void 0) { - pp[i - 1] = prev + "(?:\\/|" + twoStar + ")?"; + pp[i2 - 1] = prev + "(?:\\/|" + twoStar + ")?"; } else if (next !== GLOBSTAR) { - pp[i - 1] = prev + "(?:\\/|\\/" + twoStar + "\\/)" + next; - pp[i + 1] = GLOBSTAR; + pp[i2 - 1] = prev + "(?:\\/|\\/" + twoStar + "\\/)" + next; + pp[i2 + 1] = GLOBSTAR; } }); - return pp.filter((p) => p !== GLOBSTAR).join("/"); + return pp.filter((p2) => p2 !== GLOBSTAR).join("/"); }).join("|"); const [open, close] = set2.length > 1 ? ["(?:", ")"] : ["", ""]; re = "^" + open + re + close + "$"; @@ -10930,55 +9729,55 @@ var Minimatch = class { } return this.regexp; } - slashSplit(p) { + slashSplit(p2) { if (this.preserveMultipleSlashes) { - return p.split("/"); - } else if (this.isWindows && /^\/\/[^\/]+/.test(p)) { - return ["", ...p.split(/\/+/)]; + return p2.split("/"); + } else if (this.isWindows && /^\/\/[^\/]+/.test(p2)) { + return ["", ...p2.split(/\/+/)]; } else { - return p.split(/\/+/); + return p2.split(/\/+/); } } - match(f, partial = this.partial) { - this.debug("match", f, this.pattern); + match(f2, partial = this.partial) { + this.debug("match", f2, this.pattern); if (this.comment) { return false; } if (this.empty) { - return f === ""; + return f2 === ""; } - if (f === "/" && partial) { + if (f2 === "/" && partial) { return true; } - const options2 = this.options; + const options = this.options; if (this.isWindows) { - f = f.split("\\").join("/"); + f2 = f2.split("\\").join("/"); } - const ff = this.slashSplit(f); + const ff = this.slashSplit(f2); this.debug(this.pattern, "split", ff); const set2 = this.set; this.debug(this.pattern, "set", set2); let filename = ff[ff.length - 1]; if (!filename) { - for (let i = ff.length - 2; !filename && i >= 0; i--) { - filename = ff[i]; + for (let i2 = ff.length - 2; !filename && i2 >= 0; i2--) { + filename = ff[i2]; } } - for (let i = 0; i < set2.length; i++) { - const pattern = set2[i]; + for (let i2 = 0; i2 < set2.length; i2++) { + const pattern = set2[i2]; let file = ff; - if (options2.matchBase && pattern.length === 1) { + if (options.matchBase && pattern.length === 1) { file = [filename]; } const hit = this.matchOne(file, pattern, partial); if (hit) { - if (options2.flipNegate) { + if (options.flipNegate) { return true; } return !this.negate; } } - if (options2.flipNegate) { + if (options.flipNegate) { return false; } return this.negate; @@ -10993,11 +9792,11 @@ minimatch.escape = escape; minimatch.unescape = unescape; // src/utils/fs.ts -function isSupportedFileType(path2) { - return path2.split(".").pop().toLowerCase() === "md"; +function isSupportedFileType(path3) { + return path3.split(".").pop().toLowerCase() === "md"; } -function pathMatchesPattern(path2, pattern) { - return path2.startsWith(pattern) || minimatch(path2, pattern); +function pathMatchesPattern(path3, pattern) { + return path3.startsWith(pattern) || minimatch(path3, pattern); } // src/algorithms/osr/osr-note-graph.ts @@ -11017,28 +9816,26 @@ var OsrNoteGraph = class { this.pageranks = {}; graph.reset(); } - processLinks(path2) { - if (this.incomingLinks[path2] === void 0) { - this.incomingLinks[path2] = []; + processLinks(path3) { + if (this.incomingLinks[path3] === void 0) { + this.incomingLinks[path3] = []; } - const targetLinks = this.vaultNoteLinkInfoFinder.getResolvedTargetLinksForNotePath(path2) || /* c8 ignore next */ - {}; + const targetLinks = this.vaultNoteLinkInfoFinder.getResolvedTargetLinksForNotePath(path3) || {}; for (const targetPath in targetLinks) { if (this.incomingLinks[targetPath] === void 0) this.incomingLinks[targetPath] = []; if (isSupportedFileType(targetPath)) { const linkCount = targetLinks[targetPath]; this.incomingLinks[targetPath].push({ - sourcePath: path2, + sourcePath: path3, linkCount }); - graph.link(path2, targetPath, linkCount); + graph.link(path3, targetPath, linkCount); } } } calcNoteLinkStat(notePath, noteEaseList) { let linkTotal = 0, linkPGTotal = 0, totalLinkCount = 0; - for (const statObj of this.incomingLinks[notePath] || /* c8 ignore next */ - []) { + for (const statObj of this.incomingLinks[notePath] || []) { const ease = noteEaseList.getEaseByPath(statObj.sourcePath); if (ease) { linkTotal += statObj.linkCount * this.pageranks[statObj.sourcePath] * ease; @@ -11046,8 +9843,7 @@ var OsrNoteGraph = class { totalLinkCount += statObj.linkCount; } } - const outgoingLinks = this.vaultNoteLinkInfoFinder.getResolvedTargetLinksForNotePath(notePath) || /* c8 ignore next */ - {}; + const outgoingLinks = this.vaultNoteLinkInfoFinder.getResolvedTargetLinksForNotePath(notePath) || {}; for (const outgoingLink in outgoingLinks) { const ease = noteEaseList.getEaseByPath(outgoingLink); const linkCount = outgoingLinks[outgoingLink]; @@ -11089,10 +9885,10 @@ var DataStore = class _DataStore { // src/topic-path.ts var TopicPath = class _TopicPath { - constructor(path2) { - if (path2 == null) throw "null path"; - if (path2.some((str) => str.includes("/"))) throw "path entries must not contain '/'"; - this.path = path2; + constructor(path3) { + if (path3 == null) throw "null path"; + if (path3.some((str) => str.includes("/"))) throw "path entries must not contain '/'"; + this.path = path3; } get hasPath() { return this.path.length > 0; @@ -11144,15 +9940,15 @@ var TopicPath = class _TopicPath { isSameOrAncestorOf(topicPath) { if (this.isEmptyPath) return topicPath.isEmptyPath; if (this.path.length > topicPath.path.length) return false; - for (let i = 0; i < this.path.length; i++) { - if (this.path[i] != topicPath.path[i]) return false; + for (let i2 = 0; i2 < this.path.length; i2++) { + if (this.path[i2] != topicPath.path[i2]) return false; } return true; } static getTopicPathFromCardText(cardText) { - var _a2; - const path2 = (_a2 = cardText.trimStart().match(OBSIDIAN_TAG_AT_STARTOFLINE_REGEX)) == null ? void 0 : _a2.slice(-1)[0]; - return (path2 == null ? void 0 : path2.length) > 0 ? _TopicPath.getTopicPathFromTag(path2) : null; + var _a; + const path3 = (_a = cardText.trimStart().match(OBSIDIAN_TAG_AT_STARTOFLINE_REGEX)) == null ? void 0 : _a.slice(-1)[0]; + return (path3 == null ? void 0 : path3.length) > 0 ? _TopicPath.getTopicPathFromTag(path3) : null; } static getTopicPathsFromTagList(tagList) { const result = []; @@ -11171,8 +9967,8 @@ var TopicPath = class _TopicPath { if (tag == null || tag.length == 0) throw "Null/empty tag"; if (tag[0] != "#") throw "Tag must start with #"; if (tag.length == 1) throw "Invalid tag"; - const path2 = tag.replace("#", "").split("/").filter((str) => str); - return new _TopicPath(path2); + const path3 = tag.replace("#", "").split("/").filter((str) => str); + return new _TopicPath(path3); } static getFolderPathFromFilename(noteFile, settings) { let result = _TopicPath.emptyPath; @@ -11276,8 +10072,8 @@ var FlashcardReviewSequencer = class { return this.cardSequencer.currentCard; } get currentQuestion() { - var _a2; - return (_a2 = this.currentCard) == null ? void 0 : _a2.question; + var _a; + return (_a = this.currentCard) == null ? void 0 : _a.question; } get currentDeck() { return this.cardSequencer.currentDeck; @@ -11316,17 +10112,26 @@ var FlashcardReviewSequencer = class { async processReview(response) { switch (this.reviewMode) { case 1 /* Review */: - await this.processReview_ReviewMode(response); + await this.processReviewReviewMode(response); break; case 0 /* Cram */: - await this.processReview_CramMode(response); + await this.processReviewCramMode(response); break; } } - async processReview_ReviewMode(response) { + async processReviewReviewMode(response) { if (response != 3 /* Reset */ || this.currentCard.hasSchedule) { + const oldSchedule = this.currentCard.scheduleInfo; this.currentCard.scheduleInfo = this.determineCardSchedule(response, this.currentCard); await DataStore.getInstance().questionWriteSchedule(this.currentQuestion); + if (oldSchedule) { + const today = globalDateProvider.today.valueOf(); + const nDays = Math.ceil( + (oldSchedule.dueDateAsUnix - today) / TICKS_PER_DAY + ); + this.dueDateFlashcardHistogram.decrement(nDays); + } + this.dueDateFlashcardHistogram.increment(this.currentCard.scheduleInfo.interval); } if (response == 3 /* Reset */) { this.cardSequencer.moveCurrentCardToEndOfList(); @@ -11347,7 +10152,7 @@ var FlashcardReviewSequencer = class { await this.questionPostponementList.write(); } } - async processReview_CramMode(response) { + async processReviewCramMode(response) { if (response == 0 /* Easy */) this.deleteCurrentCard(); else { this.cardSequencer.moveCurrentCardToEndOfList(); @@ -11377,8 +10182,8 @@ var FlashcardReviewSequencer = class { return result; } async updateCurrentQuestionText(text) { - const q = this.currentQuestion.questionText; - q.actualQuestion = text; + const q2 = this.currentQuestion.questionText; + q2.actualQuestion = text; await DataStore.getInstance().questionWrite(this.currentQuestion); } }; @@ -11431,10 +10236,8 @@ var Deck2 = class _Deck { } return result; } - // // Returns a count of the number of this question's cards are present in this deck. // (The returned value would be <= question.cards.length) - // getQuestionCardCount(question) { let result = 0; result += this.getQuestionCardCountForCardListType(question, this.newFlashcards); @@ -11443,8 +10246,8 @@ var Deck2 = class _Deck { } getQuestionCardCountForCardListType(question, cards) { let result = 0; - for (let i = 0; i < cards.length; i++) { - if (Object.is(question, cards[i].question)) result++; + for (let i2 = 0; i2 < cards.length; i2++) { + if (Object.is(question, cards[i2].question)) result++; } return result; } @@ -11467,11 +10270,11 @@ var Deck2 = class _Deck { if (!topicPath.hasPath) { return this; } - const t2 = topicPath.clone(); - const deckName = t2.shift(); + const t3 = topicPath.clone(); + const deckName = t3.shift(); for (const subdeck of this.subdecks) { if (deckName === subdeck.deckName) { - return subdeck._getOrCreateDeck(t2, createAllowed); + return subdeck._getOrCreateDeck(t3, createAllowed); } } let result = null; @@ -11482,7 +10285,7 @@ var Deck2 = class _Deck { /* parent */ ); this.subdecks.push(subdeck); - result = subdeck._getOrCreateDeck(t2, createAllowed); + result = subdeck._getOrCreateDeck(t3, createAllowed); } return result; } @@ -11514,22 +10317,20 @@ var Deck2 = class _Deck { this.appendCardToRootDeck(cardObj); } else { for (const topicPath of topicPathList.list) { - this.appendCard_SingleTopic(topicPath, cardObj); + this.appendCardSingleTopic(topicPath, cardObj); } } } appendCardToRootDeck(cardObj) { - this.appendCard_SingleTopic(TopicPath.emptyPath, cardObj); + this.appendCardSingleTopic(TopicPath.emptyPath, cardObj); } - appendCard_SingleTopic(topicPath, cardObj) { + appendCardSingleTopic(topicPath, cardObj) { const deck = this.getOrCreateDeck(topicPath); const cardList = deck.getCardListForCardType(cardObj.cardListType); cardList.push(cardObj); } - // // The question lists all the topics in which this card is included. // The topics are relative to the base deck, and this method must be called on that deck - // deleteQuestionFromAllDecks(question, exceptionIfMissing) { for (const card of question.cards) { this.deleteCardFromAllDecks(card, exceptionIfMissing); @@ -11540,10 +10341,8 @@ var Deck2 = class _Deck { this.deleteCardFromThisDeck(card, exceptionIfMissing); } } - // // The card's question lists all the topics in which this card is included. // The topics are relative to the base deck, and this method must be called on that deck - // deleteCardFromAllDecks(card, exceptionIfMissing) { for (const topicPath of card.question.topicPathList.list) { const deck = this.getDeck(topicPath); @@ -11572,10 +10371,10 @@ var Deck2 = class _Deck { return result; } sortSubdecksList() { - this.subdecks.sort((a, b) => { - if (a.deckName < b.deckName) { + this.subdecks.sort((a2, b2) => { + if (a2.deckName < b2.deckName) { return -1; - } else if (a.deckName > b.deckName) { + } else if (a2.deckName > b2.deckName) { return 1; } return 0; @@ -11594,15 +10393,15 @@ var Deck2 = class _Deck { result += `${indentStr}${this.deckName}\r `; indentStr += " "; - for (let i = 0; i < this.newFlashcards.length; i++) { - const card = this.newFlashcards[i]; - result += `${indentStr}New: ${i}: ${card.front}::${card.back}\r + for (let i2 = 0; i2 < this.newFlashcards.length; i2++) { + const card = this.newFlashcards[i2]; + result += `${indentStr}New: ${i2}: ${card.front}::${card.back}\r `; } - for (let i = 0; i < this.dueFlashcards.length; i++) { - const card = this.dueFlashcards[i]; - const s = card.isDue ? "Due" : "Not due"; - result += `${indentStr}${s}: ${i}: ${card.front}::${card.back}\r + for (let i2 = 0; i2 < this.dueFlashcards.length; i2++) { + const card = this.dueFlashcards[i2]; + const s2 = card.isDue ? "Due" : "Not due"; + result += `${indentStr}${s2}: ${i2}: ${card.front}::${card.back}\r `; } for (const subdeck of this.subdecks) { @@ -11617,9 +10416,9 @@ var Deck2 = class _Deck { const result = new _Deck(this.deckName, parent); result.newFlashcards = [...this.newFlashcards.filter((card) => predicate(card))]; result.dueFlashcards = [...this.dueFlashcards.filter((card) => predicate(card))]; - for (const s of this.subdecks) { + for (const s2 of this.subdecks) { const newParent = result; - const newDeck = s.copyWithCardFilter(predicate, newParent); + const newDeck = s2.copyWithCardFilter(predicate, newParent); result.subdecks.push(newDeck); } return result; @@ -11648,6 +10447,11 @@ function getTypedObjectEntries(obj) { return Object.entries(obj); } var getKeysPreserveType = Object.keys; +function mapRecord(record, transform) { + return Object.fromEntries( + Object.entries(record).map(([key, value]) => transform(key, value)) + ); +} // src/utils/numbers.ts var ValueCountDict = class { @@ -11669,8 +10473,8 @@ var ValueCountDict = class { return Math.max(...getKeysPreserveType(this.dict)) || 0; } getTotalOfValueMultiplyCount() { - const v = getTypedObjectEntries(this.dict).map(([value, count]) => value * count).reduce((a, b) => a + b, 0) || 0; - return v; + const v2 = getTypedObjectEntries(this.dict).map(([value, count]) => value * count).reduce((a2, b2) => a2 + b2, 0) || 0; + return v2; } }; var RandomNumberProvider = class { @@ -11693,7 +10497,6 @@ var WeightedRandomNumber = class _WeightedRandomNumber { static create() { return new _WeightedRandomNumber(globalRandomNumberProvider); } - // // weights is a dictionary: // first number - a key that can be returned // second number - the "bucket size" - this is a weight that influences the probability of the @@ -11704,22 +10507,22 @@ var WeightedRandomNumber = class _WeightedRandomNumber { // second number - an "index" value; 0 <= index < bucketSize getRandomValues(weights) { const total = _WeightedRandomNumber.calcTotalOfCount(weights); - if (Object.values(weights).some((i) => !Number.isInteger(i) || i < 0)) + if (Object.values(weights).some((i2) => !Number.isInteger(i2) || i2 < 0)) throw "All weights must be positive integers"; - const v = this.provider.getInteger(0, total - 1); - let x = 0; + const v2 = this.provider.getInteger(0, total - 1); + let x2 = 0; for (const kvp in weights) { const [value, count] = [Number(kvp), weights[kvp]]; - if (v < x + count) { - const index = v - x; + if (v2 < x2 + count) { + const index = v2 - x2; return [value, index]; } - x += count; + x2 += count; } throw ""; } static calcTotalOfCount(weights) { - const total = getTypedObjectEntries(weights).map(([_, count]) => count).reduce((a, b) => a + b, 0) || 0; + const total = getTypedObjectEntries(weights).map(([_2, count]) => count).reduce((a2, b2) => a2 + b2, 0) || 0; return total; } }; @@ -11861,8 +10664,8 @@ var DeckTreeIterator = class _DeckTreeIterator { return this.deckIdx != null && this.singleDeckIterator.hasCurrentCard; } get currentTopicPath() { - var _a2; - return (_a2 = this.currentDeck) == null ? void 0 : _a2.getTopicPath(); + var _a; + return (_a = this.currentDeck) == null ? void 0 : _a.getTopicPath(); } get currentDeck() { if (this.deckIdx == null) return null; @@ -11875,8 +10678,8 @@ var DeckTreeIterator = class _DeckTreeIterator { return result; } get currentQuestion() { - var _a2; - return (_a2 = this.currentCard) == null ? void 0 : _a2.question; + var _a; + return (_a = this.currentCard) == null ? void 0 : _a.question; } constructor(iteratorOrder, baseDeckTree) { this.singleDeckIterator = new SingleDeckIterator(iteratorOrder); @@ -11914,7 +10717,7 @@ var DeckTreeIterator = class _DeckTreeIterator { this.baseDeckTree.deleteCardFromAllDecks(this.currentCard, true); } if (this.iteratorOrder.cardOrder == 4 /* EveryCardRandomDeckAndCard */) { - result = this.nextCard_EveryCardRandomDeck(); + result = this.nextCardEveryCardRandomDeck(); } else { if (this.deckIdx == null) { this.chooseNextDeck(true); @@ -11938,14 +10741,14 @@ var DeckTreeIterator = class _DeckTreeIterator { case 1 /* PrevDeckComplete_Random */: { const weights = {}; let hasDeck = false; - for (let i = 0; i < this.deckArray.length; i++) { - if (this.deckArray[i].getCardCount(2 /* All */, false)) { - weights[i] = 1; + for (let i2 = 0; i2 < this.deckArray.length; i2++) { + if (this.deckArray[i2].getCardCount(2 /* All */, false)) { + weights[i2] = 1; hasDeck = true; } } if (hasDeck) { - const [deckIdx, _] = this.weightedRandomNumber.getRandomValues(weights); + const [deckIdx, _2] = this.weightedRandomNumber.getRandomValues(weights); this.deckIdx = deckIdx; } else { this.deckIdx = this.deckArray.length; @@ -11957,12 +10760,12 @@ var DeckTreeIterator = class _DeckTreeIterator { this.singleDeckIterator.setDeck(this.deckArray[this.deckIdx]); } } - nextCard_EveryCardRandomDeck() { + nextCardEveryCardRandomDeck() { const weights = {}; - for (let i = 0; i < this.deckArray.length; i++) { - const cardCount = this.deckArray[i].getCardCount(2 /* All */, false); + for (let i2 = 0; i2 < this.deckArray.length; i2++) { + const cardCount = this.deckArray[i2].getCardCount(2 /* All */, false); if (cardCount) { - weights[i] = cardCount; + weights[i2] = cardCount; } } if (Object.keys(weights).length == 0) return false; @@ -12105,8 +10908,8 @@ var _DueDateHistogram = class _DueDateHistogram { return originalInterval; } let interval = originalInterval; - outer: for (let i = 1; i <= fuzz; i++) { - for (const ivl of [originalInterval - i, originalInterval + i]) { + outer: for (let i2 = 1; i2 <= fuzz; i2++) { + for (const ivl of [originalInterval - i2, originalInterval + i2]) { if (!this.hasEntryForDays(ivl)) { interval = ivl; break outer; @@ -12157,68 +10960,8 @@ var CardDueDateHistogram = class extends DueDateHistogram { } }; -// src/note.ts -var Note = class { - get hasChanged() { - return this.questionList.some((question) => question.hasChanged); - } - get filePath() { - return this.file.path; - } - constructor(file, questionList) { - this.file = file; - this.questionList = questionList; - questionList.forEach((question) => question.note = this); - } - appendCardsToDeck(deck) { - for (const question of this.questionList) { - for (const card of question.cards) { - deck.appendCard(question.topicPathList, card); - } - } - } - debugLogToConsole(desc = "") { - var _a2; - let str = `Note: ${desc}: ${this.questionList.length} questions\r -`; - for (let i = 0; i < this.questionList.length; i++) { - const q = this.questionList[i]; - str += `[${i}]: ${q.questionType}: ${q.lineNo}: ${(_a2 = q.topicPathList) == null ? void 0 : _a2.format("|")}: ${q.questionText.original}\r -`; - } - console.debug(str); - } - async writeNoteFile(settings) { - let fileText = await this.file.read(); - for (const question of this.questionList) { - if (question.hasChanged) { - fileText = question.updateQuestionWithinNoteText(fileText, settings); - } - } - await this.file.write(fileText); - this.questionList.forEach((question) => question.hasChanged = false); - } -}; - -// src/card.ts -var Card = class extends RepetitionItem { - constructor(init) { - super(); - Object.assign(this, init); - } - get cardListType() { - return this.isNew ? 0 /* NewCard */ : 1 /* DueCard */; - } - formatSchedule() { - let result = ""; - if (this.hasSchedule) result = this.scheduleInfo.formatCardScheduleForHtmlComment(); - else result = "New"; - return result; - } -}; - -// src/parser.ts -var import_peggy = __toESM(require_peggy_min()); +// src/file.ts +var import_obsidian2 = require("obsidian"); // src/utils/strings.ts function literalStringReplace(text, searchStr, replacementStr) { @@ -12234,8 +10977,8 @@ function literalStringReplace(text, searchStr, replacementStr) { } function cyrb53(str, seed = 0) { let h12 = 3735928559 ^ seed, h22 = 1103547991 ^ seed; - for (let i = 0, ch; i < str.length; i++) { - ch = str.charCodeAt(i); + for (let i2 = 0, ch; i2 < str.length; i2++) { + ch = str.charCodeAt(i2); h12 = Math.imul(h12 ^ ch, 2654435761); h22 = Math.imul(h22 ^ ch, 1597334677); } @@ -12243,10 +10986,10 @@ function cyrb53(str, seed = 0) { h22 = Math.imul(h22 ^ h22 >>> 16, 2246822507) ^ Math.imul(h12 ^ h12 >>> 13, 3266489909); return (4294967296 * (2097151 & h22) + (h12 >>> 0)).toString(16); } -function convertToStringOrEmpty(v) { +function convertToStringOrEmpty(v2) { let result = ""; - if (v != null && v != void 0) { - result = v + ""; + if (v2 != null && v2 != void 0) { + result = v2 + ""; } return result; } @@ -12287,9 +11030,9 @@ function splitNoteIntoFrontmatterAndContent(str) { } function findLineIndexOfSearchStringIgnoringWs(lines, searchString) { let result = -1; - for (let i = 0; i < lines.length; i++) { - if (lines[i].trim() == searchString) { - result = i; + for (let i2 = 0; i2 < lines.length; i2++) { + if (lines[i2].trim() == searchString) { + result = i2; break; } } @@ -12349,15 +11092,177 @@ var MultiLineTextFinder = class _MultiLineTextFinder { } }; +// src/file.ts +var frontmatterTagPseudoLineNum = -1; +var SrTFile = class { + constructor(vault, metadataCache, file) { + this.vault = vault; + this.metadataCache = metadataCache; + this.file = file; + } + get path() { + return this.file.path; + } + get basename() { + return this.file.basename; + } + get tfile() { + return this.file; + } + async getFrontmatter() { + const fileCachedData = this.metadataCache.getFileCache(this.file) || {}; + const frontmatter = fileCachedData.frontmatter || {}; + const result = /* @__PURE__ */ new Map(); + for (const [key, value] of Object.entries(frontmatter)) { + const v2 = Array.isArray(value) && value.length > 0 ? value[0] : value; + const vStr = v2 + ""; + result.set(key, vStr); + } + return result; + } + getAllTagsFromCache() { + const fileCachedData = this.metadataCache.getFileCache(this.file) || {}; + const result = (0, import_obsidian2.getAllTags)(fileCachedData) || []; + return result; + } + getAllTagsFromText() { + var _a; + const result = []; + const fileCachedData = this.metadataCache.getFileCache(this.file) || {}; + if (((_a = fileCachedData.tags) == null ? void 0 : _a.length) > 0) { + result.push(...fileCachedData.tags); + } + result.push(...this.getFrontmatterTags(fileCachedData.frontmatter)); + return result; + } + getFrontmatterTags(frontmatter) { + const result = []; + const frontmatterTags = frontmatter != null ? frontmatter["tags"] + "" : null; + if (frontmatterTags) { + const tagStrList = parseObsidianFrontmatterTag(frontmatterTags); + for (const str of tagStrList) { + const tag = { + tag: str, + position: { + start: { + line: frontmatterTagPseudoLineNum, + col: null, + offset: null + }, + end: { + line: frontmatterTagPseudoLineNum, + col: null, + offset: null + } + } + }; + result.push(tag); + } + } + return result; + } + getQuestionContext(cardLine) { + const fileCachedData = this.metadataCache.getFileCache(this.file) || {}; + const headings = fileCachedData.headings || []; + const stack = []; + for (const heading of headings) { + if (heading.position.start.line > cardLine) { + break; + } + while (stack.length > 0 && stack[stack.length - 1].level >= heading.level) { + stack.pop(); + } + stack.push(heading); + } + const result = []; + for (const headingObj of stack) { + headingObj.heading = headingObj.heading.replace(/\[\^\d+\]/gm, "").trim(); + result.push(headingObj.heading); + } + return result; + } + getTextDirection() { + let result = 0 /* Unspecified */; + const fileCache = this.metadataCache.getFileCache(this.file); + const frontMatter = fileCache == null ? void 0 : fileCache.frontmatter; + if (frontMatter && (frontMatter == null ? void 0 : frontMatter.direction)) { + const str = (frontMatter.direction + "").toLowerCase(); + result = str == "rtl" ? 2 /* Rtl */ : 1 /* Ltr */; + } + return result; + } + async read() { + return await this.vault.read(this.file); + } + async write(content) { + await this.vault.modify(this.file, content); + } +}; + +// src/note.ts +var Note = class { + get hasChanged() { + return this.questionList.some((question) => question.hasChanged); + } + get filePath() { + return this.file.path; + } + constructor(file, questionList) { + this.file = file; + this.questionList = questionList; + questionList.forEach((question) => question.note = this); + } + appendCardsToDeck(deck) { + for (const question of this.questionList) { + for (const card of question.cards) { + deck.appendCard(question.topicPathList, card); + } + } + } + debugLogToConsole(desc = "") { + var _a; + let str = `Note: ${desc}: ${this.questionList.length} questions\r +`; + for (let i2 = 0; i2 < this.questionList.length; i2++) { + const q2 = this.questionList[i2]; + str += `[${i2}]: ${q2.questionType}: ${q2.lineNo}: ${(_a = q2.topicPathList) == null ? void 0 : _a.format("|")}: ${q2.questionText.original}\r +`; + } + console.debug(str); + } + async writeNoteFile(settings) { + let fileText = await this.file.read(); + for (const question of this.questionList) { + if (question.hasChanged) { + fileText = question.updateQuestionWithinNoteText(fileText, settings); + } + } + await this.file.write(fileText); + this.questionList.forEach((question) => question.hasChanged = false); + } +}; + +// src/card.ts +var Card = class extends RepetitionItem { + constructor(init) { + super(); + Object.assign(this, init); + } + get cardListType() { + return this.isNew ? 0 /* NewCard */ : 1 /* DueCard */; + } + formatSchedule() { + let result = ""; + if (this.hasSchedule) result = this.scheduleInfo.formatCardScheduleForHtmlComment(); + else result = "New"; + return result; + } +}; + +// src/parser.ts +var import_clozecraft = __toESM(require_dist()); + // src/question.ts -var CardType = /* @__PURE__ */ ((CardType2) => { - CardType2[CardType2["SingleLineBasic"] = 0] = "SingleLineBasic"; - CardType2[CardType2["SingleLineReversed"] = 1] = "SingleLineReversed"; - CardType2[CardType2["MultiLineBasic"] = 2] = "MultiLineBasic"; - CardType2[CardType2["MultiLineReversed"] = 3] = "MultiLineReversed"; - CardType2[CardType2["Cloze"] = 4] = "Cloze"; - return CardType2; -})(CardType || {}); var QuestionText = class _QuestionText { constructor(original, topicPathWithWs, actualQuestion, textDirection, blockId) { this.original = original; @@ -12512,280 +11417,7 @@ ${scheduleHtml}`; }; // src/parser.ts -var parser2 = null; -var oldOptions; var debugParser = false; -function areParserOptionsEqual(options1, options2) { - return options1.singleLineCardSeparator === options2.singleLineCardSeparator && options1.singleLineReversedCardSeparator === options2.singleLineReversedCardSeparator && options1.multilineCardSeparator === options2.multilineCardSeparator && options1.multilineReversedCardSeparator === options2.multilineReversedCardSeparator && options1.multilineCardEndMarker === options2.multilineCardEndMarker && options1.convertHighlightsToClozes === options2.convertHighlightsToClozes && options1.convertBoldTextToClozes === options2.convertBoldTextToClozes && options1.convertCurlyBracketsToClozes === options2.convertCurlyBracketsToClozes; -} -function generateParser(options2) { - let grammar = null; - if (debugParser) { - if (grammar === null) { - grammar = generateGrammar(options2); - } - console.log( - "The parsers grammar is provided below. You can test it with https://peggyjs.org/online.html." - ); - console.log({ - info: "Copy the grammar by right-clicking on the property grammar and copying it as a string. Then, paste it in https://peggyjs.org/online.html.", - grammar - }); - } - if (parser2 === null || !areParserOptionsEqual(options2, oldOptions)) { - oldOptions = Object.assign({}, options2); - grammar = generateGrammar(options2); - if (debugParser) { - const t0 = Date.now(); - parser2 = (0, import_peggy.generate)(grammar); - const t1 = Date.now(); - console.log("New parser generated in " + (t1 - t0) + " milliseconds."); - } else { - parser2 = (0, import_peggy.generate)(grammar); - } - } else { - if (debugParser) { - console.log("Parser already exists. No need to generate a new parser."); - } - } - return parser2; -} -function generateGrammar(options2) { - let clozes_grammar = ""; - const card_rules_list = ["html_comment", "tilde_code", "backprime_code"]; - if (options2.singleLineCardSeparator.trim() !== "") card_rules_list.push("inline_rev_card"); - if (options2.singleLineCardSeparator.trim() !== "") card_rules_list.push("inline_card"); - if (options2.multilineReversedCardSeparator.trim() !== "") - card_rules_list.push("multiline_rev_card"); - if (options2.multilineCardSeparator.trim() !== "") card_rules_list.push("multiline_card"); - const cloze_rules_list = []; - if (options2.convertHighlightsToClozes) cloze_rules_list.push("cloze_equal"); - if (options2.convertBoldTextToClozes) cloze_rules_list.push("cloze_star"); - if (options2.convertCurlyBracketsToClozes) cloze_rules_list.push("cloze_bracket"); - if (cloze_rules_list.length > 0) { - card_rules_list.push("cloze_card"); - const cloze_rules = cloze_rules_list.join(" / "); - clozes_grammar = ` -cloze_card -= $(multiline_before_cloze? cloze_line (multiline_after_cloze)? (newline annotation)?) { - return createParsedQuestionInfo(CardType.Cloze,text().trimEnd(),location().start.line-1,location().end.line-1); -} - -cloze_line -= ((!cloze_text (inline_code / non_newline))* cloze_text) text_line_nonterminated? - -multiline_before_cloze -= (!cloze_line nonempty_text_line)+ - -multiline_after_cloze -= e:(!(newline separator_line) text_line1)+ - -cloze_text -= ${cloze_rules} - -cloze_equal -= cloze_mark_equal (!cloze_mark_equal non_newline)+ cloze_mark_equal - -cloze_mark_equal -= "==" - -cloze_star -= cloze_mark_star (!cloze_mark_star non_newline)+ cloze_mark_star - -cloze_mark_star -= "**" - -cloze_bracket -= cloze_mark_bracket_open (!cloze_mark_bracket_close non_newline)+ cloze_mark_bracket_close - -cloze_mark_bracket_open -= "{{" - -cloze_mark_bracket_close -= "}}" -`; - } - card_rules_list.push("loose_line"); - const card_rules = card_rules_list.join(" / "); - return `{ - // The fallback case is important if we want to test the rules with https://peggyjs.org/online.html - const CardTypeFallBack = { - SingleLineBasic: 0, - SingleLineReversed: 1, - MultiLineBasic: 2, - MultiLineReversed: 3, - Cloze: 4, - }; - - // The fallback case is important if we want to test the rules with https://peggyjs.org/online.html - const createParsedQuestionInfoFallBack = (cardType, text, firstLineNum, lastLineNum) => { - return {cardType, text, firstLineNum, lastLineNum}; - }; - - const CardType = options.CardType ? options.CardType : CardTypeFallBack; - const createParsedQuestionInfo = options.createParsedQuestionInfo ? options.createParsedQuestionInfo : createParsedQuestionInfoFallBack; - - function filterBlocks(b) { - return b.filter( (d) => d !== null ) - } -} - -main -= blocks:block* { return filterBlocks(blocks); } - -/* The input text to the parser contains arbitrary text, not just card definitions. -Hence we fallback to matching on loose_line. The result from loose_line is filtered out by filterBlocks() */ -block -= ${card_rules} - -html_comment -= $("" (html_comment / .))* "-->" newline?) { - return null; -} - -/* Obsidian tag definition: https://help.obsidian.md/Editing+and+formatting/Tags#Tag+format */ -tag -= $("#" + name:([a-zA-Z/\\-_] { return 1; } / [0-9]{ return 0;})+ &{ - // check if it is a valid Obsidian tag - (Tags must contain at least one non-numerical character) - return name.includes(1); -}) - -inline_card -= e:inline newline? { return e; } - -inline -= $(left:(!inline_mark (inline_code / non_newline))+ inline_mark right:text_till_newline (newline annotation)?) { - return createParsedQuestionInfo(CardType.SingleLineBasic,text(),location().start.line-1,location().end.line-1); -} - -inline_rev_card -= e:inline_rev newline? { return e; } - -inline_rev -= left:(!inline_rev_mark (inline_code / non_newline))+ inline_rev_mark right:text_till_newline (newline annotation)? { - return createParsedQuestionInfo(CardType.SingleLineReversed,text(),location().start.line-1,location().end.line-1); -} - -multiline_card -= c:multiline separator_line { - return c; -} - -multiline -= arg1:multiline_before multiline_mark arg2:multiline_after { - return createParsedQuestionInfo(CardType.MultiLineBasic,(arg1+"${options2.multilineCardSeparator}\\n"+arg2.trimEnd()),location().start.line-1,location().end.line-2); -} - -multiline_before -= $(!multiline_mark nonempty_text_line)+ - -multiline_after -= $(!separator_line (tilde_code / backprime_code / text_line))+ - -inline_code -= $("\`" (!"\`" .)* "\`") - -tilde_code -= $( - " "* left:$tilde_marker text_line - (!(middle:$tilde_marker &{ return left.length===middle.length;}) (tilde_code / text_line))* - (right:$tilde_marker &{ return left.length===right.length; }) - newline -) { return null; } - -tilde_marker -= "~~~" "~"* - -backprime_code -= $( - " "* left:$backprime_marker text_line - (!(middle:$backprime_marker &{ return left.length===middle.length;}) (backprime_code / text_line))* - (right:$backprime_marker &{ return left.length===right.length; }) - newline -) { return null; } - -backprime_marker -= "\`\`\`" "\`"* - -multiline_rev_card -= @multiline_rev separator_line - -multiline_rev -= arg1:multiline_rev_before multiline_rev_mark arg2:multiline_rev_after { - return createParsedQuestionInfo(CardType.MultiLineReversed,(arg1+"${options2.multilineReversedCardSeparator}\\n"+arg2.trimEnd()),location().start.line-1,location().end.line-2); -} - -multiline_rev_before -= $(!multiline_rev_mark nonempty_text_line)+ - -multiline_rev_after -= $(!separator_line text_line)+ - -${clozes_grammar} - -inline_mark -= "${options2.singleLineCardSeparator}" - -inline_rev_mark -= "${options2.singleLineReversedCardSeparator}" - -multiline_mark -= optional_whitespaces "${options2.multilineCardSeparator}" optional_whitespaces newline - -multiline_rev_mark -= optional_whitespaces "${options2.multilineReversedCardSeparator}" optional_whitespaces newline - -end_card_mark -= "${options2.multilineCardEndMarker}" - -separator_line -= end_card_mark optional_whitespaces newline - -text_line_nonterminated -= $nonempty_text_till_newline - -nonempty_text_line -= nonempty_text_till_newline newline - -text_line -= @$text_till_newline newline - -// very likely, it is possible to homogeneize/modify the rules to use only either 'text_line1' or 'text_line' -text_line1 -= newline @$text_till_newline - -loose_line -= $((text_till_newline newline) / nonempty_text_till_newline) { - return null; - } - -annotation -= $("" .)+ "-->") - -nonempty_text_till_newline -= $(inline_code / non_newline)+ - -text_till_newline -= $non_newline* - -non_newline -= [^\\n] - -newline -= $[\\n] - -empty_line -= $(whitespace_char* [\\n]) - -nonemptyspace -= [^ \\f\\t\\v\\u0020\\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000\\ufeff] - -optional_whitespaces -= whitespace_char* - -whitespace_char = ([ \\f\\t\\v\\u0020\\u00a0\\u1680\\u2000-\\u200a\\u2028\\u2029\\u202f\\u205f\\u3000\\ufeff]) -`; -} function setDebugParser(value) { debugParser = value; } @@ -12800,22 +11432,111 @@ var ParsedQuestionInfo = class { return lineNum >= this.firstLineNum && lineNum <= this.lastLineNum; } }; -function parseEx(text, options2) { +function markerInsideCodeBlock(text, marker, markerIndex) { + let goingBack = markerIndex - 1, goingForward = markerIndex + marker.length; + let backTicksBefore = 0, backTicksAfter = 0; + while (goingBack >= 0) { + if (text[goingBack] === "`") backTicksBefore++; + goingBack--; + } + while (goingForward < text.length) { + if (text[goingForward] === "`") backTicksAfter++; + goingForward++; + } + return backTicksBefore % 2 === 1 && backTicksAfter % 2 === 1; +} +function hasInlineMarker(text, marker) { + if (marker.length == 0) return false; + const markerIdx = text.indexOf(marker); + if (markerIdx === -1) return false; + return !markerInsideCodeBlock(text, marker, markerIdx); +} +function parse(text, options) { if (debugParser) { console.log("Text to parse:\n<<<" + text + ">>>"); } - let cards = []; - try { - if (!options2) throw new Error("No parser options provided."); - const parser3 = generateParser(options2); - cards = parser3.parse(text + "\n\n\n", { - CardType, - createParsedQuestionInfo: (cardType, text2, firstLineNum, lastLineNum) => { - return new ParsedQuestionInfo(cardType, text2, firstLineNum, lastLineNum); + const inlineSeparators = [ + { separator: options.singleLineCardSeparator, type: 0 /* SingleLineBasic */ }, + { separator: options.singleLineReversedCardSeparator, type: 1 /* SingleLineReversed */ } + ]; + inlineSeparators.sort((a2, b2) => b2.separator.length - a2.separator.length); + const cards = []; + let cardText = ""; + let cardType = null; + let firstLineNo = 0, lastLineNo = 0; + const clozecrafter = new import_clozecraft.ClozeCrafter(options.clozePatterns); + const lines = text.replaceAll("\r\n", "\n").split("\n"); + for (let i2 = 0; i2 < lines.length; i2++) { + const currentLine = lines[i2], currentTrimmed = lines[i2].trim(); + if (currentLine.startsWith("")) i2++; + i2++; + continue; + } + const isEmptyLine = currentTrimmed.length == 0; + const hasMultilineCardEndMarker = options.multilineCardEndMarker && currentTrimmed == options.multilineCardEndMarker; + if ( + // We've probably reached the end of a card + isEmptyLine && !options.multilineCardEndMarker || // Empty line & we're not picking up any card + isEmptyLine && cardType == null || // We've reached the end of a multi line card & + // we're using custom end markers + hasMultilineCardEndMarker + ) { + if (cardType) { + lastLineNo = i2 - 1; + cards.push( + new ParsedQuestionInfo(cardType, cardText.trimEnd(), firstLineNo, lastLineNo) + ); + cardType = null; } - }); - } catch (error) { - console.error("Unexpected error:", error); + cardText = ""; + firstLineNo = i2 + 1; + continue; + } + if (cardText.length > 0) { + cardText += "\n"; + } + cardText += currentLine.trimEnd(); + for (const { separator, type } of inlineSeparators) { + if (hasInlineMarker(currentLine, separator)) { + cardType = type; + break; + } + } + if (cardType == 0 /* SingleLineBasic */ || cardType == 1 /* SingleLineReversed */) { + cardText = currentLine; + firstLineNo = i2; + if (i2 + 1 < lines.length && lines[i2 + 1].startsWith("