Add eslint and apply quick fixes

This commit is contained in:
alexcolucci@protonmail.com 2021-12-16 09:57:19 +01:00
parent 1940e78eda
commit 81a15ade41
13 changed files with 182 additions and 161 deletions

20
.eslintrc.json Normal file
View File

@ -0,0 +1,20 @@
{
"env": {
"browser": true,
"es2021": true
},
"extends": [
"eslint:recommended",
"plugin:@typescript-eslint/recommended"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
"ecmaVersion": 13,
"sourceType": "module"
},
"plugins": [
"@typescript-eslint"
],
"rules": {
}
}

View File

@ -15,6 +15,9 @@
"@rollup/plugin-node-resolve": "^9.0.0",
"@rollup/plugin-typescript": "^6.0.0",
"@types/node": "^14.17.4",
"@typescript-eslint/eslint-plugin": "^5.7.0",
"@typescript-eslint/parser": "^5.7.0",
"eslint": "^8.4.1",
"obsidian": "https://github.com/obsidianmd/obsidian-api/tarball/master",
"rollup": "^2.52.2",
"ts-node": "^9.1.0",

File diff suppressed because one or more lines are too long

View File

@ -16,7 +16,7 @@ export abstract class Card {
containsCode: boolean
modelName: string
constructor(id: number, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[], inserted: boolean, mediaNames: string[], containsCode: boolean = false) {
constructor(id: number, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[], inserted: boolean, mediaNames: string[], containsCode = false) {
this.id = id
this.deckName = deckName
this.initialContent = initialContent
@ -43,14 +43,14 @@ export abstract class Card {
// return false
// }
let fields = Object.entries(card.fields)
const fields = Object.entries(card.fields)
// This is the case of a switch from a model to another one. It cannot be handeled
if (fields.length !== Object.entries(this.fields).length) {
return true
}
for (let field of fields) {
let fieldName = field[0]
for (const field of fields) {
const fieldName = field[0]
if (field[1].value !== this.fields[fieldName]) {
return false
}

View File

@ -2,7 +2,7 @@ import { codeDeckExtension, sourceDeckExtension } from 'src/constants';
import { Card } from "src/entities/card";
export class Flashcard extends Card {
constructor(id: number = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted: boolean = false, mediaNames: string[], containsCode: boolean) {
constructor(id = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted = false, mediaNames: string[], containsCode: boolean) {
super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames, containsCode)
this.modelName = this.reversed ? `Obsidian-basic-reversed` : `Obsidian-basic`
if (fields["Source"]) {
@ -13,8 +13,8 @@ export class Flashcard extends Card {
}
}
public getCard(update: boolean = false): object {
let card: any = {
public getCard(update = false): object {
const card: any = {
"deckName": this.deckName,
"modelName": this.modelName,
"fields": this.fields,
@ -29,7 +29,7 @@ export class Flashcard extends Card {
}
public getMedias(): object[] {
let medias: object[] = []
const medias: object[] = []
this.mediaBase64Encoded.forEach((data, index) => {
medias.push({
"filename": this.mediaNames[index],

View File

@ -2,7 +2,7 @@ import { codeDeckExtension, sourceDeckExtension } from 'src/constants';
import { Card } from "src/entities/card";
export class Inlinecard extends Card {
constructor(id: number = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted: boolean = false, mediaNames: string[], containsCode: boolean) {
constructor(id = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted = false, mediaNames: string[], containsCode: boolean) {
super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames, containsCode) // ! CHANGE []
this.modelName = this.reversed ? `Obsidian-basic-reversed` : `Obsidian-basic`
@ -14,8 +14,8 @@ export class Inlinecard extends Card {
}
}
public getCard(update: boolean = false): object {
let card: any = {
public getCard(update = false): object {
const card: any = {
"deckName": this.deckName,
"modelName": this.modelName,
"fields": this.fields,
@ -30,7 +30,7 @@ export class Inlinecard extends Card {
}
public getMedias(): object[] {
let medias: object[] = []
const medias: object[] = []
this.mediaBase64Encoded.forEach((data, index) => {
medias.push({
"filename": this.mediaNames[index],

View File

@ -2,7 +2,7 @@ import { codeDeckExtension, sourceDeckExtension } from 'src/constants';
import { Card } from "src/entities/card";
export class Spacedcard extends Card {
constructor(id: number = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted: boolean = false, mediaNames: string[], containsCode: boolean) {
constructor(id = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted = false, mediaNames: string[], containsCode: boolean) {
super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames, containsCode)
this.modelName = `Obsidian-spaced`
if (fields["Source"]) {
@ -13,9 +13,9 @@ export class Spacedcard extends Card {
}
}
public getCard(update: boolean = false): object {
public getCard(update = false): object {
let card: any = {
const card: any = {
"deckName": this.deckName,
"modelName": this.modelName,
"fields": this.fields,
@ -30,7 +30,7 @@ export class Spacedcard extends Card {
}
public getMedias(): object[] {
let medias: object[] = []
const medias: object[] = []
this.mediaBase64Encoded.forEach((data, index) => {
medias.push({
"filename": this.mediaNames[index],

View File

@ -3,7 +3,7 @@ import { Anki } from 'src/services/anki'
export class SettingsTab extends PluginSettingTab {
display(): void {
let { containerEl } = this
const { containerEl } = this
const plugin = (this as any).plugin
containerEl.empty()

View File

@ -34,13 +34,13 @@ export class Regex {
this.cardsToDelete = /^\s*(?:\n)(?:\^(\d{13}))(?:\n\s*?)?/gm
// https://regex101.com/r/WxuFI2/1
this.globalTagsSplitter = /\[\[(.*?)\]\]|#([\p{L}:\-_\/]+)|([\p{L}:\-_\/]+)/gmiu
this.globalTagsSplitter = /\[\[(.*?)\]\]|#([\p{L}:\-_/]+)|([\p{L}:\-_/]+)/gmiu
this.tagHierarchy = /\//gm
// Cards
let flags = "gimu"
const flags = "gimu"
// https://regex101.com/r/p3yQwY/2
let str = "( {0,3}[#]*)((?:[^\\n]\\n?)+?)(#" + settings.flashcardsTag + "(?:[\/-]reverse)?)((?: *#[\\p{Letter}\\-\\/_]+)*) *?\\n+((?:[^\\n]\\n?)*?(?=\\^\\d{13}|$))(?:\\^(\\d{13}))?"
let str = "( {0,3}[#]*)((?:[^\\n]\\n?)+?)(#" + settings.flashcardsTag + "(?:[/-]reverse)?)((?: *#[\\p{Letter}\\-\\/_]+)*) *?\\n+((?:[^\\n]\\n?)*?(?=\\^\\d{13}|$))(?:\\^(\\d{13}))?"
this.flashscardsWithTag = new RegExp(str, flags)
// https://regex101.com/r/Ixtzlv/1
@ -52,7 +52,7 @@ export class Regex {
this.cardsInlineStyle = new RegExp(str, flags)
// https://regex101.com/r/HOXF5E/1
str = "( {0,3}[#]*)((?:[^\\n]\\n?)+?)(#" + settings.flashcardsTag + "[\/-]spaced)((?: *#[\\p{Letter}-]+)*) *\\n?(?:\\^(\\d{13}))?"
str = "( {0,3}[#]*)((?:[^\\n]\\n?)+?)(#" + settings.flashcardsTag + "[/-]spaced)((?: *#[\\p{Letter}-]+)*) *\\n?(?:\\^(\\d{13}))?"
this.cardsSpacedStyle = new RegExp(str, flags)
}
}

View File

@ -16,10 +16,10 @@ export class Anki {
}
public async storeMediaFiles(cards: Card[]) {
let actions: any[] = []
const actions: any[] = []
for (let card of cards) {
for (let media of card.getMedias()) {
for (const card of cards) {
for (const media of card.getMedias()) {
actions.push({
"action": "storeMediaFile",
"params": media
@ -35,7 +35,7 @@ export class Anki {
}
public async storeCodeHighlightMedias() {
let fileExists = await this.invoke(
const fileExists = await this.invoke(
"retrieveMediaFile",
6,
{
@ -43,19 +43,19 @@ export class Anki {
})
if (!fileExists) {
let highlightjs = {
const highlightjs = {
"action": "storeMediaFile", "params": {
"filename": "_highlight.js",
"data": highlightjsBase64
}
}
let highlightjsInit = {
const highlightjsInit = {
"action": "storeMediaFile", "params": {
"filename": "_highlightInit.js",
"data": hihglightjsInitBase64
}
}
let highlightjcss = {
const highlightjcss = {
"action": "storeMediaFile", "params": {
"filename": "_highlight.css",
"data": highlightCssBase64
@ -66,7 +66,7 @@ export class Anki {
}
public async addCards(cards: Card[]): Promise<number[]> {
let notes: any = []
const notes: any = []
cards.forEach(card => notes.push(card.getCard(false)))
@ -92,9 +92,9 @@ export class Anki {
// This means that the delta from the current tags on Anki and the generated one should be added/removed
// That's what the current approach does, but in the future if the API it is made more consistent
// then mergeTags(...) is not needed anymore
let ids: number[] = []
const ids: number[] = []
for (let card of cards) {
for (const card of cards) {
updateActions.push({
"action": "updateNoteFields",
"params": {
@ -139,11 +139,11 @@ export class Anki {
}
private mergeTags(oldTags: string[], newTags: string[], cardId: number) {
let actions = []
const actions = []
// Find tags to Add
for (let tag of newTags) {
let index = oldTags.indexOf(tag)
for (const tag of newTags) {
const index = oldTags.indexOf(tag)
if (index > -1) {
oldTags.splice(index, 1)
} else {
@ -158,7 +158,7 @@ export class Anki {
}
// All Tags to delete
for (let tag of oldTags) {
for (const tag of oldTags) {
actions.push({
"action": "removeTags",
"params": {
@ -171,7 +171,7 @@ export class Anki {
return actions
}
private invoke(action: string, version: number = 6, params = {}): any {
private invoke(action: string, version = 6, params = {}): any {
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.addEventListener('error', () => reject('failed to issue request'));
@ -181,10 +181,10 @@ export class Anki {
if (Object.getOwnPropertyNames(response).length != 2) {
throw 'response has an unexpected number of fields';
}
if (!response.hasOwnProperty('error')) {
if (!Object.prototype.hasOwnProperty.call(response, "error")) {
throw 'response is missing required error field';
}
if (!response.hasOwnProperty('result')) {
if (!Object.prototype.hasOwnProperty.call(response, "result")) {
throw 'response is missing required result field';
}
if (response.error) {
@ -216,13 +216,13 @@ export class Anki {
codeExtension = codeDeckExtension
}
let css = ".card {\r\n font-family: arial;\r\n font-size: 20px;\r\n text-align: center;\r\n color: black;\r\n background-color: white;\r\n}\r\n\r\n.tag::before {\r\n\tcontent: \"#\";\r\n}\r\n\r\n.tag {\r\n color: white;\r\n background-color: #9F2BFF;\r\n border: none;\r\n font-size: 11px;\r\n font-weight: bold;\r\n padding: 1px 8px;\r\n margin: 0px 3px;\r\n text-align: center;\r\n text-decoration: none;\r\n cursor: pointer;\r\n border-radius: 14px;\r\n display: inline;\r\n vertical-align: middle;\r\n}\r\n"
let front = `{{Front}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>${codeScriptContent}`
let back = `{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}${sourceFieldContent}`
let frontReversed = `{{Back}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>${codeScriptContent}`
let backReversed = `{{FrontSide}}\n\n<hr id=answer>\n\n{{Front}}${sourceFieldContent}`
let prompt = `{{Prompt}}\r\n<p class=\"tags\">🧠spaced {{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>${codeScriptContent}`
let promptBack = `{{FrontSide}}\n\n<hr id=answer>🧠 Review done.${sourceFieldContent}`
const css = ".card {\r\n font-family: arial;\r\n font-size: 20px;\r\n text-align: center;\r\n color: black;\r\n background-color: white;\r\n}\r\n\r\n.tag::before {\r\n\tcontent: \"#\";\r\n}\r\n\r\n.tag {\r\n color: white;\r\n background-color: #9F2BFF;\r\n border: none;\r\n font-size: 11px;\r\n font-weight: bold;\r\n padding: 1px 8px;\r\n margin: 0px 3px;\r\n text-align: center;\r\n text-decoration: none;\r\n cursor: pointer;\r\n border-radius: 14px;\r\n display: inline;\r\n vertical-align: middle;\r\n}\r\n"
const front = `{{Front}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>${codeScriptContent}`
const back = `{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}${sourceFieldContent}`
const frontReversed = `{{Back}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>${codeScriptContent}`
const backReversed = `{{FrontSide}}\n\n<hr id=answer>\n\n{{Front}}${sourceFieldContent}`
const prompt = `{{Prompt}}\r\n<p class=\"tags\">🧠spaced {{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>${codeScriptContent}`
const promptBack = `{{FrontSide}}\n\n<hr id=answer>🧠 Review done.${sourceFieldContent}`
let classicFields = ["Front", "Back"]
let promptFields = ["Prompt"]
@ -231,7 +231,7 @@ export class Anki {
promptFields = promptFields.concat("Source")
}
let obsidianBasic = {
const obsidianBasic = {
"action": "createModel",
"params": {
"modelName": `Obsidian-basic${sourceExtension}${codeExtension}`,
@ -247,7 +247,7 @@ export class Anki {
}
}
let obsidianBasicReversed = {
const obsidianBasicReversed = {
"action": "createModel",
"params": {
"modelName": `Obsidian-basic-reversed${sourceExtension}${codeExtension}`,
@ -268,7 +268,7 @@ export class Anki {
}
}
let obsidianSpaced = {
const obsidianSpaced = {
"action": "createModel",
"params": {
"modelName": `Obsidian-spaced${sourceExtension}${codeExtension}`,

View File

@ -43,14 +43,14 @@ export class CardsService {
this.updateFile = false
this.totalOffset = 0
this.notifications = []
let filePath = activeFile.basename
let sourcePath = activeFile.path
let fileCachedMetadata = this.app.metadataCache.getFileCache(activeFile)
let vaultName = this.app.vault.getName()
const filePath = activeFile.basename
const sourcePath = activeFile.path
const fileCachedMetadata = this.app.metadataCache.getFileCache(activeFile)
const vaultName = this.app.vault.getName()
let globalTags: string[] = undefined
// Parse frontmatter
let frontmatter = fileCachedMetadata.frontmatter
const frontmatter = fileCachedMetadata.frontmatter
let deckName = this.settings.deck
if (frontmatter) {
deckName = parseFrontMatterEntry(frontmatter, "cards-deck") || this.settings.deck
@ -66,13 +66,13 @@ export class CardsService {
}
globalTags = this.parseGlobalTags(this.file)
// TODO with empty check that does not call ankiCards line
let ankiBlocks = this.parser.getAnkiIDsBlocks(this.file)
let ankiCards = ankiBlocks ? await this.anki.getCards(this.getAnkiIDs(ankiBlocks)) : undefined
const ankiBlocks = this.parser.getAnkiIDsBlocks(this.file)
const ankiCards = ankiBlocks ? await this.anki.getCards(this.getAnkiIDs(ankiBlocks)) : undefined
let cards: Card[] = this.parser.generateFlashcards(this.file, deckName, vaultName, filePath, globalTags)
let [cardsToCreate, cardsToUpdate, cardsNotInAnki] = this.filterByUpdate(ankiCards, cards)
let cardIds: number[] = this.getCardsIds(ankiCards, cards)
let cardsToDelete: number[] = this.parser.getCardsToDelete(this.file)
const cards: Card[] = this.parser.generateFlashcards(this.file, deckName, vaultName, filePath, globalTags)
const [cardsToCreate, cardsToUpdate, cardsNotInAnki] = this.filterByUpdate(ankiCards, cards)
const cardIds: number[] = this.getCardsIds(ankiCards, cards)
const cardsToDelete: number[] = this.parser.getCardsToDelete(this.file)
console.info("Flashcards: Cards to create")
console.info(cardsToCreate)
@ -82,7 +82,7 @@ export class CardsService {
console.info(cardsToDelete)
if (cardsNotInAnki) {
console.info("Flashcards: Cards not in Anki (maybe deleted)")
for (let card of cardsNotInAnki) {
for (const card of cardsNotInAnki) {
this.notifications.push(`Error: Card with ID ${card.id} is not in Anki!`)
}
}
@ -94,7 +94,7 @@ export class CardsService {
await this.insertCardsOnAnki(cardsToCreate, frontmatter, deckName)
// Update decks if needed
let deckNeedToBeChanged = await this.deckNeedToBeChanged(cardIds, deckName)
const deckNeedToBeChanged = await this.deckNeedToBeChanged(cardIds, deckName)
if (deckNeedToBeChanged) {
try {
this.anki.changeDeck(cardIds, deckName)
@ -141,17 +141,17 @@ export class CardsService {
if (this.app.vault.adapter instanceof FileSystemAdapter) {
// @ts-ignore: Unreachable code error
for (let card of cards) {
for (let media of card.mediaNames) {
let image = this.app.metadataCache.getFirstLinkpathDest(decodeURIComponent(media), sourcePath);
for (const card of cards) {
for (const media of card.mediaNames) {
const image = this.app.metadataCache.getFirstLinkpathDest(decodeURIComponent(media), sourcePath);
try {
let binaryMedia = await this.app.vault.readBinary(image)
const binaryMedia = await this.app.vault.readBinary(image)
card.mediaBase64Encoded.push(arrayBufferToBase64(binaryMedia))
} catch (err) {
Error("Error: Could not read media")
}
}
};
}
}
}
@ -159,7 +159,7 @@ export class CardsService {
if (cardsToCreate.length) {
let insertedCards = 0
try {
let ids = await this.anki.addCards(cardsToCreate)
const ids = await this.anki.addCards(cardsToCreate)
// Add IDs from response to Flashcard[]
ids.map((id: number, index: number) => {
cardsToCreate[index].id = id
@ -188,10 +188,10 @@ export class CardsService {
}
private updateFrontmatter(frontmatter: FrontMatterCache, deckName: string) {
let newFrontmatter: string = ""
let cardsDeckLine: string = `cards-deck: ${deckName}\n`
let newFrontmatter = ""
const cardsDeckLine = `cards-deck: ${deckName}\n`
if (frontmatter) {
let oldFrontmatter: string = this.file.substring(frontmatter.position.start.offset, frontmatter.position.end.offset)
const oldFrontmatter: string = this.file.substring(frontmatter.position.start.offset, frontmatter.position.end.offset)
if (!oldFrontmatter.match(this.regex.cardsDeckLine)) {
newFrontmatter = oldFrontmatter.substring(0, oldFrontmatter.length - 3) + cardsDeckLine + "---"
this.totalOffset += cardsDeckLine.length
@ -205,7 +205,7 @@ export class CardsService {
}
private writeAnkiBlocks(cardsToCreate: Card[]) {
for (let card of cardsToCreate) {
for (const card of cardsToCreate) {
// Card.id cannot be null, because if written already previously it has an ID,
// if it has been inserted it has an ID too
if (card.id !== null && !card.inserted) {
@ -218,7 +218,7 @@ export class CardsService {
}
}
card.endOffset += this.totalOffset
let offset = card.endOffset
const offset = card.endOffset
this.updateFile = true
this.file = this.file.substring(0, offset) + id + this.file.substring(offset, this.file.length + 1)
@ -245,7 +245,7 @@ export class CardsService {
if (cards.length) {
let deletedCards = 0
for (const block of ankiBlocks) {
let id = Number(block[1])
const id = Number(block[1])
// Deletion of cards that need to be deleted (i.e. blocks ID that don't have content)
if (cards.includes(id)) {
@ -269,8 +269,8 @@ export class CardsService {
}
private getAnkiIDs(blocks: RegExpMatchArray[]): number[] {
let IDs: number[] = []
for (let b of blocks) {
const IDs: number[] = []
for (const b of blocks) {
IDs.push(Number(b[1]))
}
@ -280,11 +280,11 @@ export class CardsService {
public filterByUpdate(ankiCards: any, generatedCards: Card[]) {
let cardsToCreate: Card[] = []
let cardsToUpdate: Card[] = []
let cardsNotInAnki: Card[] = []
const cardsToUpdate: Card[] = []
const cardsNotInAnki: Card[] = []
if (ankiCards) {
for (let flashcard of generatedCards) {
for (const flashcard of generatedCards) {
// Inserted means that anki blocks are available, that means that the card should
// (the user can always delete it) be in Anki
let ankiCard = undefined
@ -308,7 +308,7 @@ export class CardsService {
}
public async deckNeedToBeChanged(cardsIds: number[], deckName: string) {
let cardsInfo = await this.anki.cardsInfo(cardsIds)
const cardsInfo = await this.anki.cardsInfo(cardsIds)
console.log("Flashcards: Cards info")
console.log(cardsInfo)
if (cardsInfo.length !== 0) {
@ -322,7 +322,7 @@ export class CardsService {
let ids: number[] = []
if (ankiCards) {
for (let flashcard of generatedCards) {
for (const flashcard of generatedCards) {
let ankiCard = undefined
if (flashcard.inserted) {
ankiCard = ankiCards.filter((card: any) => Number(card.noteId) === flashcard.id)[0]
@ -336,10 +336,10 @@ export class CardsService {
return ids
}
public parseGlobalTags(file: String): string[] {
public parseGlobalTags(file: string): string[] {
let globalTags: string[] = []
let tags = file.match(/(?:cards-)?tags: ?(.*)/im)
const tags = file.match(/(?:cards-)?tags: ?(.*)/im)
globalTags = tags ? tags[1].match(this.regex.globalTagsSplitter) : []
if (globalTags) {

View File

@ -24,7 +24,7 @@ export class Parser {
}
public generateFlashcards(file: string, deck: string, vault: string, note: string, globalTags: string[] = []): Flashcard[] {
let contextAware = this.settings.contextAwareMode
const contextAware = this.settings.contextAwareMode
let cards: Flashcard[] = []
let headings: any = []
@ -39,7 +39,7 @@ export class Parser {
cards = cards.concat(this.generateSpacedCards(file, headings, deck, vault, note, globalTags))
cards.sort((a, b) => a.endOffset - b.endOffset)
let defaultAnkiTag = this.settings.defaultAnkiTag
const defaultAnkiTag = this.settings.defaultAnkiTag
if (defaultAnkiTag) {
for (const card of cards) {
card.tags.push(defaultAnkiTag)
@ -57,9 +57,9 @@ export class Parser {
* @param headingLevel The level of the first ancestor heading, i.e. the number of #.
*/
private getContext(headings: any, index: number, headingLevel: number): string[] {
let context: string[] = []
const context: string[] = []
let currentIndex: number = index
let goalLevel: number = 6
let goalLevel = 6
let i = headings.length - 1
// Get the level of the first heading before the index (i.e. above the current line)
@ -82,7 +82,7 @@ export class Parser {
// Search for the other headings
for (i; i >= 0; i--) {
let currentLevel = headings[i][1].length
const currentLevel = headings[i][1].length
if (currentLevel == goalLevel && headings[i].index < currentIndex) {
currentIndex = headings[i].index
goalLevel = currentLevel - 1
@ -95,36 +95,36 @@ export class Parser {
}
private generateSpacedCards(file: string, headings: any, deck: string, vault: string, note: string, globalTags: string[] = []) {
let contextAware = this.settings.contextAwareMode
let cards: Spacedcard[] = []
let matches = [...file.matchAll(this.regex.cardsSpacedStyle)]
const contextAware = this.settings.contextAwareMode
const cards: Spacedcard[] = []
const matches = [...file.matchAll(this.regex.cardsSpacedStyle)]
for (let match of matches) {
let reversed: boolean = false
for (const match of matches) {
const reversed = false
let headingLevel = -1
if (match[1]) {
headingLevel = match[1].trim().length !== 0 ? match[1].trim().length : -1
}
// Match.index - 1 because otherwise in the context there will be even match[1], i.e. the question itself
let context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
const context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
let originalPrompt = match[2].trim()
const originalPrompt = match[2].trim()
let prompt = contextAware ? [...context, match[2].trim()].join(`${this.settings.contextSeparator}`) : match[2].trim()
let medias: string[] = this.getImageLinks(prompt)
medias = medias.concat(this.getAudioLinks(prompt))
prompt = this.parseLine(prompt, vault)
let endingLine = match.index + match[0].length
let tags: string[] = this.parseTags(match[4], globalTags)
let id: number = match[5] ? Number(match[5]) : -1
let inserted: boolean = match[5] ? true : false
let fields: any = { "Prompt": prompt }
const endingLine = match.index + match[0].length
const tags: string[] = this.parseTags(match[4], globalTags)
const id: number = match[5] ? Number(match[5]) : -1
const inserted: boolean = match[5] ? true : false
const fields: any = { "Prompt": prompt }
if (this.settings.sourceSupport) {
fields["Source"] = note
}
let containsCode = this.containsCode([prompt])
const containsCode = this.containsCode([prompt])
let card = new Spacedcard(id, deck, originalPrompt, fields, reversed, endingLine, tags, inserted, medias, containsCode)
const card = new Spacedcard(id, deck, originalPrompt, fields, reversed, endingLine, tags, inserted, medias, containsCode)
cards.push(card)
}
@ -132,24 +132,24 @@ export class Parser {
}
private generateInlineCards(file: string, headings: any, deck: string, vault: string, note: string, globalTags: string[] = []) {
let contextAware = this.settings.contextAwareMode
let cards: Inlinecard[] = []
let matches = [...file.matchAll(this.regex.cardsInlineStyle)]
const contextAware = this.settings.contextAwareMode
const cards: Inlinecard[] = []
const matches = [...file.matchAll(this.regex.cardsInlineStyle)]
for (let match of matches) {
for (const match of matches) {
if (match[2].toLowerCase().startsWith("cards-deck") || match[2].toLowerCase().startsWith("tags")) {
continue
}
let reversed: boolean = match[3].trim().toLowerCase() === ':::'
const reversed: boolean = match[3].trim().toLowerCase() === ':::'
let headingLevel = -1
if (match[1]) {
headingLevel = match[1].trim().length !== 0 ? match[1].trim().length : -1
}
// Match.index - 1 because otherwise in the context there will be even match[1], i.e. the question itself
let context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
const context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
let originalQuestion = match[2].trim()
const originalQuestion = match[2].trim()
let question = contextAware ? [...context, match[2].trim()].join(`${this.settings.contextSeparator}`) : match[2].trim()
let answer = match[4].trim()
let medias: string[] = this.getImageLinks(question)
@ -158,17 +158,17 @@ export class Parser {
question = this.parseLine(question, vault)
answer = this.parseLine(answer, vault)
let endingLine = match.index + match[0].length
let tags: string[] = this.parseTags(match[5], globalTags)
let id: number = match[6] ? Number(match[6]) : -1
let inserted: boolean = match[6] ? true : false
let fields: any = { "Front": question, "Back": answer }
const endingLine = match.index + match[0].length
const tags: string[] = this.parseTags(match[5], globalTags)
const id: number = match[6] ? Number(match[6]) : -1
const inserted: boolean = match[6] ? true : false
const fields: any = { "Front": question, "Back": answer }
if (this.settings.sourceSupport) {
fields["Source"] = note
}
let containsCode = this.containsCode([question, answer])
const containsCode = this.containsCode([question, answer])
let card = new Inlinecard(id, deck, originalQuestion, fields, reversed, endingLine, tags, inserted, medias, containsCode)
const card = new Inlinecard(id, deck, originalQuestion, fields, reversed, endingLine, tags, inserted, medias, containsCode)
cards.push(card)
}
@ -176,17 +176,17 @@ export class Parser {
}
private generateCardsWithTag(file: string, headings: any, deck: string, vault: string, note: string, globalTags: string[] = []) {
let contextAware = this.settings.contextAwareMode
let cards: Flashcard[] = []
let matches = [...file.matchAll(this.regex.flashscardsWithTag)]
const contextAware = this.settings.contextAwareMode
const cards: Flashcard[] = []
const matches = [...file.matchAll(this.regex.flashscardsWithTag)]
for (let match of matches) {
let reversed: boolean = match[3].trim().toLowerCase() === `#${this.settings.flashcardsTag}-reverse` || match[3].trim().toLowerCase() === `#${this.settings.flashcardsTag}/reverse`
let headingLevel = match[1].trim().length !== 0 ? match[1].length : -1
for (const match of matches) {
const reversed: boolean = match[3].trim().toLowerCase() === `#${this.settings.flashcardsTag}-reverse` || match[3].trim().toLowerCase() === `#${this.settings.flashcardsTag}/reverse`
const headingLevel = match[1].trim().length !== 0 ? match[1].length : -1
// Match.index - 1 because otherwise in the context there will be even match[1], i.e. the question itself
let context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
const context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
let originalQuestion = match[2].trim()
const originalQuestion = match[2].trim()
let question = contextAware ? [...context, match[2].trim()].join(`${this.settings.contextSeparator}`) : match[2].trim()
let answer = match[5].trim()
let medias: string[] = this.getImageLinks(question)
@ -195,17 +195,17 @@ export class Parser {
question = this.parseLine(question, vault)
answer = this.parseLine(answer, vault)
let endingLine = match.index + match[0].length
let tags: string[] = this.parseTags(match[4], globalTags)
let id: number = match[6] ? Number(match[6]) : -1
let inserted: boolean = match[6] ? true : false
let fields: any = { "Front": question, "Back": answer }
const endingLine = match.index + match[0].length
const tags: string[] = this.parseTags(match[4], globalTags)
const id: number = match[6] ? Number(match[6]) : -1
const inserted: boolean = match[6] ? true : false
const fields: any = { "Front": question, "Back": answer }
if (this.settings.sourceSupport) {
fields["Source"] = note
}
let containsCode = this.containsCode([question, answer])
const containsCode = this.containsCode([question, answer])
let card = new Flashcard(id, deck, originalQuestion, fields, reversed, endingLine, tags, inserted, medias, containsCode)
const card = new Flashcard(id, deck, originalQuestion, fields, reversed, endingLine, tags, inserted, medias, containsCode)
cards.push(card)
}
@ -213,7 +213,7 @@ export class Parser {
}
public containsCode(str: string[]): boolean {
for (let s of str) {
for (const s of str) {
if (s.match(this.regex.codeBlock)) {
return true
}
@ -231,15 +231,15 @@ export class Parser {
}
private getImageLinks(str: string) {
let wikiMatches = str.matchAll(this.regex.wikiImageLinks)
let markdownMatches = str.matchAll(this.regex.markdownImageLinks)
let links: string[] = []
const wikiMatches = str.matchAll(this.regex.wikiImageLinks)
const markdownMatches = str.matchAll(this.regex.markdownImageLinks)
const links: string[] = []
for (let wikiMatch of wikiMatches) {
for (const wikiMatch of wikiMatches) {
links.push(wikiMatch[1])
}
for (let markdownMatch of markdownMatches) {
for (const markdownMatch of markdownMatches) {
links.push(decodeURIComponent(markdownMatch[1]))
}
@ -247,10 +247,10 @@ export class Parser {
}
private getAudioLinks(str: string) {
let wikiMatches = str.matchAll(this.regex.wikiAudioLinks)
let links: string[] = []
const wikiMatches = str.matchAll(this.regex.wikiAudioLinks)
const links: string[] = []
for (let wikiMatch of wikiMatches) {
for (const wikiMatch of wikiMatches) {
links.push(wikiMatch[1])
}
@ -258,13 +258,13 @@ export class Parser {
}
private substituteObsidianLinks(str: string, vaultName: string) {
let linkRegex = /\[\[(.+?)(?:\|(.+))?\]\]/gmi
const linkRegex = /\[\[(.+?)(?:\|(.+))?\]\]/gmi
vaultName = encodeURIComponent(vaultName)
return str.replace(linkRegex, (match, filename, rename) => {
let href = `obsidian://open?vault=${vaultName}&file=${encodeURIComponent(filename)}.md`
let fileRename = rename ? rename : filename
let link = `<a href="${href}">[[${fileRename}]]</a>`
const href = `obsidian://open?vault=${vaultName}&file=${encodeURIComponent(filename)}.md`
const fileRename = rename ? rename : filename
const link = `<a href="${href}">[[${fileRename}]]</a>`
return link
})
}
@ -281,12 +281,12 @@ export class Parser {
}
private mathToAnki(str: string) {
let mathBlockRegex = /(\$\$)(.*?)(\$\$)/gis
const mathBlockRegex = /(\$\$)(.*?)(\$\$)/gis
str = str.replace(mathBlockRegex, function (match, p1, p2) {
return '\\\\[' + escapeMarkdown(p2) + ' \\\\]'
})
let mathInlineRegex = /(\$)(.*?)(\$)/gi
const mathInlineRegex = /(\$)(.*?)(\$)/gi
str = str.replace(mathInlineRegex, function (match, p1, p2) {
return '\\\\(' + escapeMarkdown(p2) + '\\\\)'
})
@ -295,10 +295,10 @@ export class Parser {
}
private parseTags(str: string, globalTags: string[]): string[] {
let tags: string[] = [...globalTags]
const tags: string[] = [...globalTags]
if (str) {
for (let tag of str.split("#")) {
for (const tag of str.split("#")) {
let newTag = tag.trim()
if (newTag) {
// Replace obsidian hierarchy tags delimeter \ with anki delimeter ::

View File

@ -1,10 +1,8 @@
import { Vault, TFile} from 'obsidian';
export function arrayBufferToBase64(buffer: ArrayBuffer): string {
var binary = "";
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
let binary = "";
const bytes = new Uint8Array(buffer);
const len = bytes.byteLength;
for (let i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
@ -18,14 +16,14 @@ export function arraysEqual(a: string[], b: string[]) {
a.sort();
b.sort();
for (var i = 0; i < a.length; ++i) {
for (let i = 0; i < a.length; ++i) {
if (a[i] !== b[i]) return false;
}
return true;
}
export function escapeMarkdown(string: string, skips: string[] = []) {
let replacements: any = [
const replacements: any = [
[/\*/g, "\\*", "asterisks"],
[/#/g, "\\#", "number signs"],
[/\//g, "\\/", "slashes"],
@ -39,10 +37,10 @@ export function escapeMarkdown(string: string, skips: string[] = []) {
[/_/g, "\\_", "underscores"],
];
return replacements.reduce(function (string: string, replacement: any) {
let name = replacement[2];
return replacements.reduce(function (s: string, replacement: any) {
const name = replacement[2];
return name && skips.indexOf(name) !== -1
? string
: string.replace(replacement[0], replacement[1]);
? s
: s.replace(replacement[0], replacement[1]);
}, string);
}